第 17 篇 把 checkpoint 间隔、并行 writer 与湖表提交的对齐关系讲清楚了:入湖作业一旦背压,提交延迟会跟着拉长,小文件治理压力也会上升。但「背压」本身是什么、在管道里怎么一层层传上去、Web UI 里哪个数字代表瓶颈——以及倾斜、checkpoint 连锁失败、consumer rebalance 风暴、RocksDB OOM、savepoint 跨版本恢复失败这些生产里反复出现的故障模式——需要单独收束成一篇运维地图。
本文是 流式数据处理系列 的末篇,不再引入新机制,而是把前面 17 篇的机制串成:
- 背压:credit-based 流控、传播链、Flink Web UI / REST metrics 的读法。
- 五类典型故障:每种给出触发条件、观测信号、止血步骤与长期修复方向。
- 四引擎对照:Flink、Kafka Streams、Spark Structured Streaming、RisingWave 在状态模型、交付语义、运维复杂度、入湖成熟度上的差异表,以及不做排名的选型决策树。
环境说明:本机为 Arch Linux on WSL2(内核 6.6.87.2)、i9-12900K / 32 GB,未安装 JVM、Flink、Kafka、Spark。本文涉及的 Flink Web UI 字段、REST metrics 名称、配置项均按 Flink 1.20+ / 2.x 官方文档 与 Kafka 3.x 文档 核对;不粘贴未执行的 UI 截图或伪造的 metrics 数值。对照表中的「入湖成熟度」来自各项目官方 sink 文档与 Iceberg/Hudi/Delta 集成说明,标注版本边界,不给吞吐排名。
一、背压:比 consumer lag 更底层的信号
1.1 Lag 与背压各回答什么问题
Kafka consumer lag(消费位点落后生产位点的量)回答的是:输入侧有没有堆积压。它有用,但不够:
- lag 高,可能是下游算子慢(背压),也可能是 source 本身读得慢、分区分配不均、或 rebalance 期间暂停消费。
- lag 低,不代表管道健康:下游 sink 可能已经卡在 pre-commit,只是 source 还没被反压到停读。
背压(backpressure) 回答的是:管道内部哪一段算子处理不过来,从而把「慢」往上游传导。在 Flink 里,背压是运行时自带的流控机制,比单纯看 lag 更早暴露瓶颈。
1.2 Credit-based 背压在 Flink 里怎么工作
Flink 网络栈在 TaskManager 之间传 record 时,采用 credit-based flow control(基于信用的流控,Flink 文档 Backpressure 节)。直觉上:
- 下游 subtask 的 input gate 维护可用 credit(可接收 buffer 的额度)。
- 上游只有拿到 credit 才发送数据;credit 耗尽时上游阻塞发送,形成反压。
- credit 随下游消费 buffer、释放 back to upstream 而恢复。
这与 TCP 窗口类似,但发生在 Flink 自己的 Netty 网络层,粒度是 subtask 之间的 logical channel,不是 Kafka 分区。
flowchart LR
UP[上游 Subtask<br/>outbound buffer] -->|有 credit 才发| NET[Network buffer pool]
NET --> DOWN[下游 Subtask<br/>input gate + credit]
DOWN -->|处理慢, credit 不释放| NET
NET -->|credit 耗尽| UP
UP -->|阻塞 emit| SLOW[上游算子 stall]
几个容易混淆的点:
| 概念 | 含义 |
|---|---|
| Backpressure 比例 | 某 subtask 在采样窗口内「因等待 credit / buffer 而 idle」的时间占比 |
| Busy 比例 | subtask 实际在处理 record 的时间占比 |
| Idle 比例 | 既不在 busy 也不在 backpressure 的等待(例如等 watermark、等 checkpoint barrier) |
背压高不一定等于 CPU 满:可能是下游 sink IO 慢、RocksDB compaction 拖住、或单 subtask 热 key 导致处理队列堆积——CPU 利用率仍可能不均衡。
1.3 背压传播链:从 sink 往上找根因
背压几乎总是从管道最窄处向上传导。典型传播链:
flowchart BT
SINK["Sink 慢<br/>(Iceberg commit / JDBC / 外部 API)"]
AGG["重状态算子<br/>(window / join / 大 keyBy)"]
SHUF["Shuffle / keyBy<br/>(倾斜时分区热点)"]
SRC["Source<br/>(Kafka poll 变慢)"]
SINK --> AGG --> SHUF --> SRC
诊断顺序(与传播方向相反,从下往上):
- 先看 sink:提交冲突重试、外部系统限流、批量写太小导致 IO 放大(见 第 17 篇)。
- 再看有状态的中间算子:窗口 state 膨胀、RocksDB compaction 压力(见 第 12、13 篇)。
- 看 shuffle / keyBy:是否出现 subtask backpressure 显著高于 peers(倾斜前兆,见 第 8 篇)。
- 最后看 source:若 source subtask 也 backpressure 高,说明反压已传到读端;Kafka consumer 会减慢 poll,lag 随后上升。
不要把第一步就调成「增大 source 并行度」——若瓶颈在 sink,加 source 只会把堆积从 Kafka 挪到 Flink 内部 state / network buffer,最终 OOM。
1.4 读 Flink Web UI 与 REST metrics
Web UI:Back Pressure 列
打开 Flink Web UI → Job → Overview → Back Pressure(或 Operators 页的 backpressure 指示)。Flink 对算子做周期性采样(默认基于 stack sample),给出三档:
| UI 显示 | 含义 | 建议动作 |
|---|---|---|
| OK | 采样期内 backpressure 比例低 | 继续观察其它指标 |
| LOW | 轻度背压 | 记录是否与 checkpoint、业务高峰相关 |
| HIGH | 显著背压 | 优先定位该算子及下游 |
Web UI 的 backpressure 是按算子 / subtask 聚合的采样结果,不是瞬时精确值。看到 HIGH 时,点进 Subtasks 对比各 subtask 的 backpressure 与 Records Sent/Received 是否均衡。
关键 REST / Metrics 名称
以下名称以 Flink 1.20+ JobManager REST 与 metrics 体系为准(具体路径随 minor 版本可能带算子 ID 前缀):
| 指标 | 作用 |
|---|---|
backPressuredTimeMsPerSecond /
softBackPressuredTimeMsPerSecond |
背压时间速率 |
busyTimeMsPerSecond |
忙碌时间速率 |
numRecordsInPerSecond /
numRecordsOutPerSecond |
吞吐是否某 subtask 明显偏低 |
checkpointing.duration /
lastCheckpointDuration |
checkpoint 变慢常与背压共存 |
buffers.inPoolUsage /
buffers.outPoolUsage |
network buffer 池使用率过高时易放大背压 |
Kafka source 还需对照 consumer
lag(Burrow、Kafka Exporter、或 broker
DescribeGroups),但 lag 与 Flink backpressure
要联读:lag 升 + source subtask
backpressure 低 → 可能 consumer 配置或 rebalance 问题;lag
升 + 全链 HIGH → 下游算子或 sink 瓶颈。
与 checkpoint 的交互
背压会拉长 aligned checkpoint 的 barrier 对齐时间(见 第 10
篇):慢算子迟迟不 ack barrier,Coordinator
等超时。Flink 提供 unaligned checkpoint
缓解 barrier 在慢通道上的排队,但会增加 in-flight record
快照开销。背压 chronic 时,应先修瓶颈,而不是无限拉长
checkpoint.timeout。
二、故障模式一:数据倾斜(Skew)
2.1 机制
keyBy 把相同 key 路由到同一
subtask(KeyGroup 映射见 第
8 篇)。当 key 分布长尾——例如按 user_id
聚合而头部用户占 30% 流量——单个 subtask 承担远超平均的处理与
state,表现为:
- 该 subtask backpressure HIGH,同算子其它 subtask OK。
- Records Received 在 subtask 间差几个数量级。
- RocksDB 单实例磁盘与 block cache 压力远高于 peers(第 13 篇)。
2.2 观测信号
| 信号 | 在哪里看 |
|---|---|
| subtask 间 in/out records 极度不均 | Web UI Subtasks |
| 单 TM CPU / 单 RocksDB 目录大小异常 | 主机监控 + TM 日志 |
| checkpoint 某 subtask ack 总是最慢 | Checkpoint history |
| Kafka 分区消费速度一致但 Flink 侧不均 | 说明 skew 在 keyBy 之后(自定义分区器或 key 选错) |
2.3 止血与修复
短期止血(不改业务语义):
- 提高全局并行度有时能缓解 KeyGroup 切分,但对「同一 key 必须同 subtask」的热 key 无效。
- 限制 source 输入速率(Flink
rate-limit或 Kafkamax.poll.records调小)防止热 subtask OOM。
结构性修复(按场景选):
- 两阶段聚合:热 key 先加随机 salt 局部预聚合,再去 salt 全局聚合(适用于 count/sum/min/max 等可结合半环)。
- 自定义 KeyGroup 或 rebalance 热 key:把极少数 super hot key 拆到 side output 单独处理。
- 改 key 设计:按
(user_id, hash(user_id) % N)复合 key 把热点拆桶(下游再 merge)。 - 窗口改设计:会话窗口对 skew 极敏感;评估滚动窗口 + 更粗粒度 key。
倾斜的根因往往在业务 key 选错,不是「再调 10 个 RocksDB 参数」能解决的。
三、故障模式二:Checkpoint 超时连锁
3.1 机制
CheckpointCoordinator 触发 snapshot 后,等待所有算子 ack barrier。任一算子超时未 ack → 本次 checkpoint FAILED → 作业状态仍在上一次成功 checkpoint;若连续失败,根据配置可能 fail job(见 第 10 篇)。
连锁典型路径:
flowchart TD
A[下游 sink 慢 / 背压] --> B[barrier 对齐时间变长]
B --> C[checkpoint duration 超 timeout]
C --> D[checkpoint 失败]
D --> E[无新成功 CP, 状态与 offset 停滞]
E --> F[重启恢复距离变长 + lag 堆积]
F --> A
与 第 17
篇 的交叉点:Iceberg/Hudi commit 在
notifyCheckpointComplete 执行,commit
慢会拖长「端到端 checkpoint 完成时间」,表现为 checkpoint
成功但 端到端可见延迟变大;若 commit 在
pre-commit 阶段阻塞,则直接表现为 checkpoint 失败。
3.2 观测信号
| 信号 | 说明 |
|---|---|
numberOfFailedCheckpoints 持续增加 |
JobManager metrics |
lastCheckpointDuration 接近或超过
checkpoint.timeout |
REST / UI |
日志
Checkpoint expired before completing |
TaskManager / JM 日志 |
| aligned barrier 在某一 operator 卡住 | checkpoint.start_to_sync
类分解指标(版本依赖) |
3.3 止血与修复
- 先消除背压根因(上一节、sink
提交调优),而不是先把
checkpoint.timeout调到极大——timeout 只是掩盖。 - 调 interval 与 min
pause:
execution.checkpointing.interval与min-pause-between-checkpoints避免上一次 snapshot 未完成又触发下一次(堆积 snapshot 线程与 IO)。 - 启用 unaligned checkpoint(Flink 文档 Unaligned Checkpoints):适合 barrier 在慢 shuffle 边排队的情况;代价是 state 略增。
- 增量 checkpoint(RocksDB 后端,第 12 篇):降低全量 snapshot 上传体积与 duration。
- 缩小 state:TTL、清理无用 key、窗口改小、避免把大 blob 放进 ValueState。
- 入湖作业:拉长 commit 间隔、写端预聚合、异步 compaction 错峰(第 17 篇、lakehouse 第 17 章)。
四、故障模式三:Kafka Rebalance 风暴
4.1 机制
Consumer group 成员变化(作业扩缩容、TM 重启、session
超时、max.poll.interval.ms 内未 poll)会触发
partition rebalance(见 第
5 篇)。Rebalance 期间分区分配暂停,Flink Kafka source
可能:
- 停止读取若干分区 → 背压暂时缓解但 lag 跳变。
- 频繁 rebalance → 重复消费窗口扩大(at-least-once 下需下游幂等;exactly-once 依赖 checkpoint 与事务协调,见 第 14、15 篇)。
Rebalance 风暴指:短时间内多次 rebalance,consumer 大部分时间在做分配而非消费,lag 单调上升,Flink 作业吞吐骤降甚至 checkpoint 连续失败。
常见触发:
| 触发 | 说明 |
|---|---|
max.poll.interval.ms 过小 |
一次 poll 循环内处理时间过长(大 state restore、GC pause) |
session.timeout.ms 与 heartbeat 不匹配 |
网络抖动或 GC 导致 member 被踢 |
| 作业频繁 cancel/restart | 平台滚动发布未用 savepoint 或 rescale 不当 |
| Cooperative rebalance 与旧 consumer 混部 | 协议不一致导致反复 join |
4.2 观测信号
- Kafka broker 日志 /
kafka-consumer-groups.sh --describe频繁显示 rebalance。 - Flink TM 日志
partitions revoked/assigned密集出现。 - Consumer JoinGroup / SyncGroup 延迟 metrics 飙升(若启用)。
- Lag 阶梯上升,与发布窗口相关。
4.3 止血与修复
- 调大
max.poll.interval.ms:必须大于「最坏情况下一次 poll 循环耗时」(含处理 + checkpoint barrier);Flink Kafka source 文档建议与 checkpoint 间隔、record 处理时间联调。 - 稳定 consumer group 成员:避免无 savepoint 的硬重启;使用 第 11 篇 的 savepoint 升级流程。
- Cooperative sticky assignor(Kafka 2.4+):减少 rebalance 时的分区迁移量(Flink 内置 partition 分配与 Kafka consumer 交互需对照所用 Connector 版本文档)。
- 控制 TM 数量变化:rescaling 会改变 source 并行度与 partition 消费关系,尽量在低峰做并预先评估 lag。
- Debezium / Connect 管道(第 16
篇):Connect worker rebalance 与 Flink 不同栈,但 Kafka
侧 lag 症状类似,需分开查 Connect
statustopic 与 Flink 作业。
五、故障模式四:RocksDB State Backend OOM
5.1 机制
EmbeddedRocksDBStateBackend 在每个 subtask 进程内嵌 RocksDB 实例(第 12 篇)。OOM 并不总是 JVM heap 先爆——常见路径:
| 路径 | 原因 |
|---|---|
| JVM heap OOM | 过大 value 在 heap 序列化、Network buffer、managed memory 与 heap 争抢 |
| 进程 RSS OOM(被 cgroup 杀) | RocksDB block cache + memtable + index/filter block 超出 TM 容器 limit |
| 磁盘满 | compaction 跟不上写入,SST 层数暴涨 |
| native memory 泄漏 | RocksDB / JNI bug 或 iterator 未关闭(少见但需排查) |
窗口 state + 长 TTL(第 9、13 篇)是最常见的 state 体积驱动因素。
5.2 观测信号
- TM 日志
OutOfMemoryError、Killed(dmesg 可见 OOM killer)。 - RocksDB
metrics:
live-sst-files-size、estimate-num-keys持续上升不回落。 - Checkpoint 体积线性增长(第 10 篇 实验口径)。
- 单 subtask 所在 TM 磁盘使用率远高于其它 TM(倾斜 + RocksDB 叠加)。
5.3 止血与修复
- 增大 TM memory / RocksDB block cache
配置(
state.backend.rocksdb.memory.managed等,以 Flink 版本文档为准)——前提是已排除 state 设计问题。 - 启用 incremental checkpoint:降低单次 checkpoint 峰值 IO,但不减少 live state 总量。
- State TTL + 清理策略:过期 key 在 compaction 后物理删除有延迟,需预留磁盘水位。
- 换 state 设计:会话窗口改滚动、MapState 改外部 KV、热 key 拆分。
- HashMapStateBackend 对照:state 能放进 heap 的小作业可切换(丢失增量 checkpoint 优势),见 第 9 篇 选型表。
- 与 LSM 系列对照理解 compaction:LSM-Tree 系列 中的 write amplification 直觉可直接映射到 Flink TM 磁盘与写放大。
六、故障模式五:Savepoint 不兼容
6.1 机制
Savepoint 是用户触发的、格式保留的全局一致性快照(第 11 篇),用于升级、改并行度、迁移集群。与 checkpoint 不同,savepoint 跨版本保留的期望更高,但受 状态 schema 演进规则 约束。
不兼容典型场景:
| 场景 | 结果 |
|---|---|
| 删除有状态的算子 | 恢复时报 missing operator state |
| 改算子 UID / 改算子链拓扑 | state 映射失败 |
| 改 state 类型(ValueState → ListState) | deserialization 失败 |
| 跨大版本 Flink(1.x → 2.x) | 需对照 State Evolution 与 release notes |
| 改序列化器(POJO 字段增删无默认) | compatibility 取决于
TypeSerializerSnapshot |
| 从 RocksDB 换 HashMap 或反向 | 通常需 rewrite state 或重新消费 |
Savepoint 不是备份万能药:它保存的是引擎状态,不包含 Kafka 事务未提交的消息、也不包含外部 sink 已 pre-commit 但未 commit 的副作用边界——端到端语义仍要按 第 14、15 篇理解。
6.2 观测信号
- 启动作业
Cannot map old state for operator ... StateMigrationException/ serializer 版本不匹配 stack trace。- rescale 后部分 subtask 无 state 分配。
6.3 止血与修复
- 升级前读 Flink State
Evolution:用
StateProcessor API或savepoint-dispose/ 迁移工具做 state 变换(官方示例)。 - 固定算子
UID:
uid("stable-id")避免拓扑变化导致 mapping 丢失。 - 允许 state
丢弃的变更(明确业务可重放):配置
allowNonRestoredState从 savepoint 启动,缺失算子用空 state。 - 不可兼容时:从 Kafka 指定 offset 或 timestamp 重新消费 + 重建 state(双写窗口内对下游幂等)。
- 改并行度:优先用 rescale 而非 naive restart;对照 savepoint rescaling 文档的 max parallelism 约束。
七、运维诊断总表
把五类故障与背压信号合成一张先查什么的表,便于 on-call 快速收窄:
| 现象 | 优先怀疑 | 第一屏打开 |
|---|---|---|
| 全链 backpressure HIGH,lag 随后升 | sink / 外部系统 | sink metrics、Iceberg commit 日志 |
| 单 subtask backpressure HIGH | 数据倾斜 | Subtasks records 分布 |
| checkpoint 周期性失败 | duration vs timeout、背压 | Checkpoint history、failed CP 原因 |
| lag 阶梯、发布窗口相关 | Kafka rebalance | consumer group 日志、Flink partition 分配 |
| TM 被杀 / RocksDB 盘满 | state 膨胀 / compaction | TM 磁盘、RocksDB live SST |
| 升级后无法 restore | savepoint 不兼容 | 迁移文档、算子 UID、serializer |
更系统的 lag / SLO / 告警模型见 可观测性系列;本文聚焦 Flink + Kafka 管道内的机制对齐。
八、四引擎对照:状态、语义、运维、入湖
下面比较 Apache Flink、Kafka Streams、Spark Structured Streaming、RisingWave 四个常见选型。口径固定为四个维度,不做吞吐排名,不引用无版本上下文的 benchmark 营销。
8.1 对照总表
| 维度 | Apache Flink | Kafka Streams | Spark Structured Streaming | RisingWave |
|---|---|---|---|---|
| 编程模型 | DataStream / Table API / SQL;独立集群 JM/TM | Kafka 客户端库,嵌入 JVM 进程 | Spark SQL / Dataset,微批 foreachBatch |
PostgreSQL 协议兼容 SQL;分布式 compute + storage |
| 状态模型 | KeyedState + OperatorState;RocksDB / HashMap backend;savepoint | RocksDB 本地 state store;changelog repartition topic | HDFS / cloud 目录 checkpoint + state store(版本依赖);有状态算子靠 Spark SQL 计划 | 内置存储层(自研/cloud);物化视图持久化 |
| 时间语义 | Event time + watermark 一等公民(第 2、3 篇) | Event time 通过 TimestampExtractor;窗口在
DSL 中 |
Event time 支持;微批边界与 processing 混合 | SQL 层 event time / interval 语法 |
| 交付语义 | AT_LEAST_ONCE / EXACTLY_ONCE checkpoint;2PC sink(第 14、15 篇) | EOS:processing.guarantee=exactly_once +
事务 producer;依赖 Kafka 事务 |
单次微批 idempotent + WAL offset;端到端 EOS 需 sink 配合 | 官方宣称 exactly-once 语义;以文档与部署模式为准 |
| 容错快照 | Aligned / unaligned checkpoint;savepoint 独立触发 | Kafka changelog + local state snapshot | Structured Streaming checkpoint 目录 | 内置 backup / recovery 机制 |
| 背压 | Credit-based 网络流控;Web UI backpressure 指标 | 线程模型 + max.block.ms 等;无 Flink 式全局
UI |
微批调度;背压体现为 batch 排队 | 内部流控;对外 PostgreSQL 查询延迟 |
| 运维实体 | Flink 集群(JM/TM)、独立扩缩 | 每个应用一个 JVM,随 app 启停 | Spark 集群 / Databricks 等 | RisingWave 集群 / cloud |
| Kafka 耦合 | Kafka Connector 独立;可换 Pulsar 等 | 仅 Kafka 作为源与存储 | Kafka source 为之一 | Kafka 作为 source 之一 |
| 入湖成熟度 | Iceberg / Hudi / Delta 官方 Flink sink;2PC 与 checkpoint 对齐(lakehouse 第 19 章、本系列 17) | 无官方 Iceberg sink;通常 Kafka Connect 或下游 Flink | Iceberg / Delta 官方 Structured Streaming sink;微批提交 | Iceberg sink 在 roadmap / 集成中(以发行版文档为准) |
| 典型边界 | 复杂 CEP、大状态、低延迟;运维成本最高 | Kafka 内轻量聚合;状态受本地磁盘限制 | 与 Spark 批统一;延迟下限为 micro-batch | PG 生态实时物化;运维新栈 |
版本锚定:Kafka 3.x;Flink 1.20+ / 2.x;Spark 3.x Structured Streaming;RisingWave 以当前开源发行版文档为准——升级前核对各 release note。
8.2 状态模型差异(展开)
Flink 把 state 放在 TM 本地 RocksDB(或 heap),checkpoint 异步上传到分布式存储;state 大小与 TM 磁盘、checkpoint 存储 triple 相关。KeyGroup 与 max parallelism 绑定 rescale 能力(第 9、11 篇)。
Kafka Streams state 是 partition 绑定的本地 RocksDB,变更日志可选写入 internal changelog topic 做恢复。没有独立「集群快照协调器」——恢复靠 changelog replay + local snapshot。适合 state 小于单机磁盘、作业数可控的场景。
Spark Structured Streaming
将有状态算子(例如 dropDuplicates、mapGroupsWithState)的
state 存于 checkpoint 目录;执行上仍是
micro-batch 驱动,state 更新发生在 batch
边界。与 Flink 的 continuous operator 模型不同,延迟与
trigger 直接相关。
RisingWave 把 state 放进自研存储(云版与开源版架构文档描述为 decoupled compute/storage),对用户呈现为 物化视图 与 SQL 查询。状态运维更像「数据库副本 + recovery」,而不是「每个 TM 一套 RocksDB」。
8.3 交付语义差异(展开)
端到端 exactly-once 都需要 source offset 可重放 + 引擎内部一致性点 + sink 幂等或 2PC 三者对齐(第 14 篇)。
- Flink:checkpoint 完成 → Kafka offset
与 operator state 一致 →
TwoPhaseCommitSink在 notifyComplete 提交外部系统(第 15 篇)。 - Kafka Streams:EOS 依赖 Kafka
事务 producer 与 consumer
isolation.level=read_committed(第 6 篇);输出 topic 写入与 consumer offset 提交在同一事务。 - Spark SS:WAL 记录 batch offset;sink 需 idempotent write 或 delta/iceberg 事务 API;微批失败重跑可能重复写 batch,靠 sink 去重。
- RisingWave:以 sink connector 文档描述的语义为准;对接 Iceberg 等仍需核对是否参与 2PC。
8.4 入湖成熟度(展开,不做排名)
「成熟度」这里指:官方维护的 sink、与表格式 checkpoint / 2PC 协议的对齐文档是否完整、生产案例是否可核对,不是「谁更快」。
| 引擎 | Iceberg | Hudi | Delta | 备注 |
|---|---|---|---|---|
| Flink | 官方 Flink sink;checkpoint 2PC(本系列 15、17) | Hudi Flink writer | 社区/连接器变化需查版本 | 与 lakehouse 第 19 章 对读 |
| Kafka Streams | 通常经 Connect 或下游引擎 | 同左 | 同左 | 库本身不写湖 |
| Spark SS | 官方 writeStream.format("iceberg") |
官方 Hudi spark 集成 | 官方 Delta streaming | 微批提交间隔 = trigger |
| RisingWave | 以 roadmap / connector 文档为准 | 同左 | 同左 | 部署前核对发行版 |
九、选型决策树(不做排名)
决策树回答「什么约束下选谁」,不回答「谁最强」。
flowchart TD
START[需要流式计算] --> Q1{已有 Spark 批平台<br/>且延迟秒级可接受?}
Q1 -->|是| SS[Spark Structured Streaming<br/>统一 SQL/批流]
Q1 -->|否| Q2{状态与逻辑是否<br/>仅依赖 Kafka?}
Q2 -->|是, 轻量| KS[Kafka Streams<br/>嵌入应用]
Q2 -->|否| Q3{需要复杂 event time<br/>窗口 / CEP / 大状态?}
Q3 -->|是| FL[Flink<br/>独立集群]
Q3 -->|否| Q4{团队更熟 PostgreSQL<br/>物化视图语义?}
Q4 -->|是| RW[RisingWave]
Q4 -->|否| FL
FL --> Q5{端到端 exactly-once 入 Iceberg?}
Q5 -->|是| FLICE[Flink + Iceberg 2PC<br/>调 checkpoint 与 compaction]
SS --> Q6{已用 Delta 为主?}
Q6 -->|是| SSD[Spark SS + Delta streaming]
读树时的硬约束(任一满足则收窄选项):
- 延迟要求:亚秒级 continuous 处理 → Flink 或 Kafka Streams;秒级以上 micro-batch 可接受 → Spark SS。
- Kafka 以外 source(Pulsar、文件、CDC 直连)→ Kafka Streams 排除。
- 入湖 exactly-once 到 Iceberg → 优先核对 Flink Iceberg sink 与 checkpoint 文档(本系列 15、17;lakehouse 19)。
- 运维主体:能否养独立 Flink 集群 / RisingWave 集群;若只能嵌入现有 JVM 服务 → Kafka Streams。
- 状态规模:单 app 状态远超单机磁盘 → Flink / Spark / RisingWave;Kafka Streams 需评估 changelog 与本地磁盘。
混合架构在数据平台里常见且合理:Debezium → Kafka → Kafka Streams 做轻量路由 → Flink 做大状态聚合 → Iceberg;决策树选的是主计算引擎,不是禁止组合。
十、系列收束与边界
10.1 本系列已覆盖的栈
| 层 | 篇目 | 核心问题 |
|---|---|---|
| 模型 | 1–3 | 流 vs 批、event time、窗口 |
| 传输 | 4–6 | Kafka 日志、ISR、事务 |
| 计算 | 7–13 | Flink 运行时、state、RocksDB |
| 语义 | 14–15 | EOS、2PC |
| CDC / 入湖 | 16–17 | Debezium、引擎侧入湖旋钮 |
| 运维 | 本篇 | 背压、故障、选型 |
与 lakehouse 系列 的分工:lakehouse 第 19 章 讲表格式侧提交与 upsert;本系列讲引擎侧 watermark、state、checkpoint、背压。
10.2 本文不展开
- 云厂商 Managed Flink / MSK 内部调度与定价。
- Flink SQL 优化器、Calcite 规则全文。
- Pulsar / Redpanda 独立成篇(与 Kafka 传输层类似,可在实际选型时对照 Kafka 篇机制)。
- 任何未标注来源的吞吐、延迟排名。
10.3 生产 checklist(可打印)
- 背压:Job Overview 无 chronic HIGH;subtask records 大致均衡。
- Checkpoint:
lastCheckpointDuration≪timeout;失败率接近 0。 - Kafka:rebalance
不在发布窗口密集发生;
max.poll.interval.ms已联调。 - State:RocksDB 磁盘水位 & TTL;checkpoint 体积无失控增长。
- Savepoint:升级前在预发验证 restore;算子 UID 稳定。
- 入湖:commit 间隔与 compaction 策略已写入 runbook(17、lakehouse 17)。
- 语义:端到端 EOS 三环节(source / 引擎 / sink)已逐项核对(14–15)。
参考资料
- Apache Flink Documentation, Backpressure, Monitoring, Checkpointing, Unaligned Checkpoints, State Backends, Savepoints, State Evolution, Fault Tolerance Guarantees, Two-Phase Commit(1.20+ / 2.x stable docs)。A 级。
- Apache Kafka Documentation, Design, Consumer, Transactions, Consumer Rebalance;KIP-98 事务语义。A 级。
- Apache Kafka Streams Documentation, Processing Guarantees, State Stores, Interactive Queries。A 级。
- Apache Spark Documentation, Structured Streaming Programming Guide, Structured Streaming + Kafka, Structured Streaming + Delta/Iceberg(Spark 3.x)。A 级。
- RisingWave Documentation, Architecture, Delivery semantics, connector 与 sink 集成(以当前发行版为准)。A 级。
- Apache Iceberg Documentation, Flink Writes;Apache Hudi / Delta Lake streaming write 文档。A 级。
- Akidau et al., The Dataflow Model(event time 与 watermark 理论基础)。A 级。
- 本系列:第 5、10、11、12、13、14、15、17 篇;lakehouse 第 17、19 章。
返回 系列目录 · 上一篇 流式入湖深化(与 Lakehouse 第 19 章对读) · (本篇为系列末篇)
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【流式数据处理】Kafka · Flink · 状态 · Exactly-Once
承接数据湖流式入湖:从 Kafka 日志与副本语义,到 Flink 事件时间、watermark、窗口、RocksDB 状态与 checkpoint,再到端到端 exactly-once 与 Debezium CDC 入湖。面向数据平台与实时工程师,补全批式湖仓之外的实时计算层。
【流式数据处理】Checkpoint 机制:Barrier 对齐与一致性快照
从 Chandy-Lamport 分布式快照到 Flink aligned/unaligned checkpoint:CheckpointCoordinator 触发—ack—完成生命周期,Kafka source 如何把 partition offset 写入 checkpoint,以及 interval、timeout、min-pause、concurrent checkpoints 的调优边界。
【流式数据处理】流处理全景:从日志到有状态计算
从批、流、微批四维度对比出发,建立「可重放日志 + 有状态计算」心智模型,厘清 Lambda/Kappa 边界与流表对偶,并给出与 lakehouse 入湖侧对称的全系列地图。
【流式数据处理】Savepoint 与升级恢复:状态演化与兼容边界
对比 Savepoint 与 Checkpoint 的生命周期与格式取舍;讲清 operator uid、rescale、schema evolution 规则,cancel/stop with savepoint 流程,Flink 版本升级恢复,以及 key serializer 不兼容等故障的排查与 State Processor API 边界。