订阅更新

State状态管理:实时计算的记忆力

Flink 实时计算 20 天 · 第 4 讲 基础 约 6 分钟读完

Keyed State · Operator State · State Backend · TTL

本文目录
  1. 📋 面试题
  2. 为什么需要State?
  3. 两大类State
  4. State Backend:状态存哪里?
  5. State TTL:状态不能无限膨胀
  6. 面试加分提示
  7. 📌 总结

📋 面试题

Flink的State有哪几种?你们用的什么State Backend?State太大了怎么办?

💡 先想30秒,再往下看答案


为什么需要State?

无状态计算(map、filter)处理一条数据就忘了。但很多业务逻辑需要「记住之前的数据」:累加值、去重集合、窗口内的数据、JOIN的缓存。这些「记忆」就是State。

两大类State

Keyed State(最常用)

按Key分区,每个Key有自己的状态。

类型 存什么 场景
ValueState 单个值 上次登录时间
ListState 列表 最近N条记录
MapState K-V映射 用户的各种属性
ReducingState 聚合值 累计金额
// ValueState示例:记住用户上次登录时间
public class LoginInterval extends KeyedProcessFunction<String, Event, Alert> {
    private ValueState<Long> lastLoginState;

    @Override
    public void open(Configuration conf) {
        lastLoginState = getRuntimeContext().getState(
            new ValueStateDescriptor<>("lastLogin", Long.class));
    }

    @Override
    public void processElement(Event event, Context ctx, Collector<Alert> out) {
        Long lastLogin = lastLoginState.value();
        if (lastLogin != null && event.getTime() - lastLogin > 30 * 86400000L) {
            out.collect(new Alert("用户30天未登录"));
        }
        lastLoginState.update(event.getTime());
    }
}

Operator State(少用)

不按Key分区,整个算子实例共享一份状态。主要用在Source(如Kafka offset)和Sink。

State Backend:状态存哪里?

Backend 存储位置 特点 适用场景
HashMapStateBackend JVM堆内存 速度快,受内存限制 State小(<几GB)
EmbeddedRocksDBStateBackend 本地磁盘(RocksDB) 可存TB级State State大(生产首选)
# flink-conf.yaml
state.backend: rocksdb
state.backend.rocksdb.localdir: /data/flink/rocksdb

我们全部用RocksDB。原因很简单:HashMapStateBackend看起来快,但State稍微大点就OOM。RocksDB虽然慢一点(磁盘IO),但State可以远超内存容量,生产不炸。

💡 面试追问:RocksDB为什么慢? 因为读写要经过序列化/反序列化 + 磁盘IO。HashMapStateBackend直接在堆内存操作Java对象,不需要序列化。

State TTL:状态不能无限膨胀

State不清理会无限增长。用户ID做Key,用户量一直涨,State也一直涨。

// 设置State 7天自动过期
StateTtlConfig ttlConfig = StateTtlConfig
    .newBuilder(Time.days(7))
    .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
    .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
    .cleanupInRocksdbCompactFilter(1000)  // RocksDB压缩时清理
    .build();

ValueStateDescriptor<Long> descriptor = new ValueStateDescriptor<>("lastLogin", Long.class);
descriptor.enableTimeToLive(ttlConfig);

踩过的坑:忘记设TTL,任务跑了3个月,State从500MB涨到50GB,Checkpoint越来越慢,最后超时失败。加了7天TTL后State稳定在2GB。

面试加分提示

💡 分三层回答:

「两大类:Keyed State(按Key分区,常用ValueState/MapState)和Operator State(算子级)。

State Backend生产用RocksDB,能存TB级数据不受内存限制。HashMapStateBackend速度快但容量受限。

State必须设TTL防止无限膨胀。我们设了7天TTL,State从50GB降到2GB,Checkpoint从超时恢复到30秒内完成。」

📌 总结

记忆点 内容
两大类 Keyed State(按Key分区)+ Operator State(算子级)
常用类型 ValueState / MapState / ListState
生产Backend RocksDB(可存TB级,不受内存限制)
State TTL 必须设,防止无限膨胀
RocksDB慢的原因 序列化/反序列化 + 磁盘IO

▶ 下一篇预告:DAY 5 Checkpoint与容错


Wood聊大数据 | 9年大数据老兵,聊技术、聊职场、聊成长


小红书正文

Flink的State就是实时计算的「记忆力」。没有State,每条数据处理完就忘了,做不了累加、去重、窗口聚合。

两大类:Keyed State(按Key分区,最常用)和Operator State(算子级,主要用于Source/Sink)。Keyed State常用的有ValueState(单个值)、MapState(K-V映射)、ListState(列表)。

State存哪?生产用RocksDB。HashMapStateBackend虽然快但State大了就OOM。RocksDB能存TB级数据。

大坑:State不设TTL会无限增长。我的任务跑了3个月,State从500MB涨到50GB,Checkpoint超时失败。加了7天TTL后稳定在2GB。

面试三层回答:类型→Backend选型→TTL防膨胀,每一层都有实战佐证。

刷题进度保存在当前浏览器