
Flink 滑动窗口作业 TaskManager RocksDB 状态膨胀 Bug 分析文档版本v1.0编写日期2026-07-21适用范围基于 Flink 1.19 的滑动窗口聚合作业RocksDB State Backend文档定位技术根因分析 修复方案1. 问题现象1.1 最显性表现Flink Checkpoint 体积持续增长运维 dashboard 上最先观察到的是——该作业的 checkpoint 大小长时间不停地涨没有收敛迹象启动初期 checkpoint 体积正常MB~GB 级别运行 N 小时后checkpoint 体积持续单调上升明显与业务规模脱钩即便输入流量稳定checkpoint 仍持续增长——这是典型的状态后端内部 churn不是数据规模问题这一条是最早、最易发现的信号也是触发本次排查的直接原因。1.2 下钻后的内层证据顺着 checkpoint 体积异常这条线追到 TaskManager 本地 RocksDB 目录发现实际数据 sst 文件总数很少4 个 sst 文件合计约64KB26K 6K 1.3K 31KMANIFEST 单文件达到 447MB且持续单调增长目录归属路径示例/tmp/tm_xxx/job_xxx_op_WindowOperator_xxx/__3_3__uuid_xxx/db/即某 WindowOperator 的第 3 个并行度、第 3 个 subtask 的 RocksDB 实例1.3 影响磁盘占用失控按约 460MB/天的增速单 subtask 一周可再涨 3GB多算子多并行度叠加后非常可观Checkpoint 自身受损体积越来越大 → barrier 对齐耗时上升 → checkpoint 时延拉长 → 长时间运行后 checkpoint 容易超时失败故障恢复时间失控RocksDB 启动需要重放 MANIFESTMANIFEST 越大恢复越慢磁盘写满风险极端情况下直接导致 TaskManager 异常退出1.4 出现规律与作业运行时间正相关越往后越严重不依赖 checkpoint 行为即可复现即便关掉 checkpoint本地 MANIFEST 仍在涨——只是这次不会再被上传到外部存储放大成 checkpoint 体积2. 排查过程按时间顺序记录本次问题的调查路径便于复盘与他人复用排查套路。2.1 第一步从运维侧看到 checkpoint 异常在 Flink Web UI / 监控大盘上观察到该作业checkpoint 大小持续单调上涨没有收敛业务输入流量、Key 数量在同一时期并未显著变化多个 WindowOperator 都有类似趋势但并非所有算子均匀分布——其中 WindowOperator 的某些并行度/subtask 增长尤为明显判断状态后端内部在持续折腾——纯数据规模增长不会跟输入解耦成这样更像是状态后端元数据层在做大量重写。2.2 第二步下钻到 TaskManager 本地磁盘顺着 checkpoint 异常选了一个增长最严重的 subtask上到对应 TaskManagerls-lh/tmp/tm_xxx/job_xxx_op_WindowOperator_xxx/__3_3__uuid_xxx/db/观察到反常现象MANIFEST*单个文件447MB*.sst数据文件仅 4 个合计64KB这种sst 几乎为空、MANIFEST 巨大的组合——数据本身不大问题在 RocksDB 的元数据/版本变更日志而不是用户数据。2.3 第三步grep RocksDB LOG 验证 churn 频率RocksDB 会在 INFO 级 LOG 中记录Flush/Compaction事件。直接在出问题实例上 grepgrep-cprocessing_window-timersLOG LOG.old.*grep-cMoving #LOG LOG.old.*grep-cEFlushing memtable|CompactingLOG LOG.old.*得到关键数字仅 LOG 当前保留的窗口约 8.5 分钟关键字出现次数Flushing memtable|Compacting30,598processing_window-timers22,500Moving #0判断Flush Compaction 速率 ≈60 次/秒—— 远超正常水平意味着 RocksDB 在疯狂写盘大量 timer 写入与作业的窗口特征一致与此同时Moving # 0提示 compaction 走的是真实合并而非 trivial move2.4 第四步交叉验证与归因把已知因素排在一起对照现象候选假设 1数据规模大候选假设 2写入 churn 元数据层候选假设 3纯内存不足sst 总大小 64KB❌ 应很大✅ churn 元数据不影响 sst✅ sst 由真实数据量决定MANIFEST 447MB❌ 不应远大于 sst✅ 每次 flush/compact 都加 VersionEdit✅ 写入频率高就涨Flush 速率 60/s❌ 正常流量下不该这么高✅ 是结果不是因✅ 内存不足 → memtable 频繁刷出业务输入未变——✅ 与本次内存变更12G→8G吻合三条假设里只有内存不足能同时解释所有现象且与近期变更记录一致。同时processing_window-timers频次高 → 提示 sliding window CountTrigger 共同放大了写入量属于助推器。2.5 第五步定位真因结合近期变更记录taskmanager 物理内存由 12G 调小到 8G算子特征三套滑动窗口10/30/60minslide30s CountTrigger.of(1) 最后合并使用 ProcessWindowFunction锁定根因链内存不足 → memtable flush 风暴 → MANIFEST 膨胀 → checkpoint 上涨。3. 根因分析3.1 真正根因TaskManager 物理内存不足memtable 被持续刷出核心机制链TaskManager 物理内存由 12G → 8G缩减 ↓ 实际写入量未减少但可用堆外内存RocksDB write buffer / block cache紧张 ↓ RocksDB memtable 频繁写满触发 flush 到 L0 ↓ L0 小文件堆积速度 compaction 消化速度 ↓ 大量新 sst 文件被创建MANIFEST 中产生海量 VersionEdit增/删文件记录 ↓ 活着的数据很少64KB但 MANIFEST 巨大447MB的反常现象关键反直觉点磁盘上真正存活的用户数据几乎没有膨胀的不是数据本身而是版本变更日志——RocksDB 每次 flush / compaction 都会在 MANIFEST 中追加一条 VersionEdit 记录频繁的 memtable flush 把 MANIFEST 写爆。3.2 助推器不是根因但显著放大症状3.2.1 CountTrigger.of(1) 导致 200 倍输出放大作业内使用了三套SlidingProcessingTimeWindows10min / 30min / 60minslide 均为 30s配合CountTrigger.of(1)sliding window 语义一条输入会被同时分配到 size/slide 个窗格三套窗口合计每条输入会被复制到20 60 120 200 个窗格CountTrigger.of(1)是每收到 1 条新元素就立即 fire注意是 FIRE 不是 FIRE_AND_PURGEreduce 累加器的 state 不会被清空一条原始事件经过 union 后变成 200 条下游记录直接推高整个流水线的写入频率3.3 写入频率量化基于真实日志统计TaskManager 上对 RocksDB LOG 取样4 个 LOG/LOG.old 文件约 8.5 分钟跨度事件出现次数8.5 分钟内折算频率Flushing memtable | Compacting30,598≈ 60 次/秒processing_window-timers提及22,500≈ 44 次/秒Moving #trivial move0—两个关键事实RocksDB LOG 文件会轮转、旧的会被清理——这 8.5 分钟只是 LOG 当前保留的窗口不代表23 小时里只有 30K 次。结合文件创建时间戳精确反推累计频率可由 ~60 次/秒 × 23 小时 ≈ 505 万次解释按单条 VersionEdit 约 90 字节估算倒推回 447MB 的 MANIFEST 大小在合理范围内。即使按这 8.5 分钟的窗口做下限估算每秒 60 次 memtable flush / compaction 本身已经是严重资源紧缺的典型信号——正常配置的 RocksDB 不会以这个速率运转。3.4 行为交叉验证✅ “sst 文件小KB 级× MANIFEST 大百 MB 级”——典型 churn 模式非数据规模问题✅Flush / Compaction频次和 MANIFEST 增速匹配——次数堆量解释一切✅ 列族名processing_window-timers大量出现——窗口密集创建/清理与 sliding window CountTrigger 行为一致4. 修复方案4.1 紧急 / 短期缓解恢复 taskmanager 内存12G → 8G 是反向操作立刻改回≥ 12G并视写入量上调重启 TaskManager清掉现有 RocksDB 实例从最近一次 checkpoint 重启后 MANIFEST 立刻归零——这是能立刻见效的临时手段但根因未根治会再次涨上来5. 复盘与防患5.1 变更管理问题建议内存/并发/分区等容量参数进入 CI/CD 卡口必须配套附上本次变更对应的负载评估/压测结论建议在 Flink UI / Prometheus 上加监控告警RocksDBFlush / Compaction速率持续 X/sRocksDBWriteStall/Stalling writes because we have N level-0 files出现频次TM 堆外内存使用率 /write-buffer使用率5.2 可观测性补丁部署以下观测项可在下次提前发现同类问题指标阈值建议含义RocksDBnum files at levelL0 10 持续写入压力超 compaction 能力RocksDBflush countrate 10/s 持续memtable 撑爆RocksDB manifest size单实例 100MBMANIFEST 异常膨胀pending compaction bytes持续 1GBcompaction backlogTM native memory used / total 85%写入缓冲即将耗尽5.3 后续 TODO6. 附录原始证据6.1 关键文件大小1 个 subtask 抽样db 目录文件清单抽样 - 4 个 sst 文件26K 6K 1.3K 31K ≈ 64KB 合计 - MANIFEST447MB6.2 RocksDB LOG grep 结果仅 LOG 当前保留窗口grep-cprocessing_window-timersLOG LOG.old.* LOG:4493 LOG.old.1784617536347429:5846 LOG.old.1784617679552965:4952 LOG.old.1784617874869913:7209grep-cMoving #LOG LOG.old.*# 全部为 0grep-cEFlushing memtable|CompactingLOG LOG.old.* LOG:7061 LOG.old.1784617536347429:7563 LOG.old.1784617679552965:7811 LOG.old.1784617874869913:8163合计processing_window-timers 出现 22,500 次FlushCompact 出现 30,598 次时间窗口 ≈ 8.5 分钟对应频率 ≈ 60 次/秒。