State状态管理:实时计算的记忆力
Keyed State · Operator State · State Backend · TTL
📋 面试题
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防膨胀,每一层都有实战佐证。