背压不是故障,而是流式系统在“呼吸”,本质是下游向上游传递的流量调节信号:我处理不过来了,请慢一点发;其产生核心是上游数据涌来速度超过下游当前消化能力,如算子处理慢、资源受限、配置失衡或外部依赖拖累,导致端到端延迟飙升、Checkpoint失败、State膨胀及内存溢出风险。

背压不是故障,而是流式系统在“呼吸”——它本质是下游向上游传递的一种流量调节信号:我处理不过来了,请慢一点发。
背压是怎么产生的
核心就一条:数据从上游涌来的速度,超过了下游当前能消化的速度。这就像水龙头开太大,而下水道太细,水就会在池子里积起来。
- 算子处理慢:比如某个 Flink 的 map 或 join 算子逻辑复杂、访问了慢速外部服务,或遇到数据倾斜
- 资源受限:TaskManager 内存不足、网络带宽打满、磁盘 IO 高、频繁 GC 占用 CPU
- 配置失衡:上游 Source 并行度为 8,下游 Sink 只有 2,天然形成“窄口”
- 外部依赖拖累:Sink 写入数据库或 HTTP 服务响应延迟升高,导致整个链路卡在末端
背压会带来哪些实际影响
它不会立刻让作业崩溃,但会让系统悄悄“生病”:
- 端到端延迟飙升:数据在算子间缓冲区排队等待,从进入系统到输出可能延迟数秒甚至分钟
- Checkpoint 失败:Barrier 被堵在背压节点前,对齐超时(默认 10 分钟),状态无法持久化
- State 持续膨胀:为等慢输入的 Barrier,快输入的数据被缓存在 state 中,内存占用不断上涨
- 内存溢出风险:尤其在使用 onBackpressureBuffer 且无界缓存时,JVM 堆可能被撑爆
背压在不同框架中怎么体现
虽然原理一致,但各系统实现方式不同,排查入口也不同:
-
Flink:Web UI 的 BackPressure 页面显示 HIGH/Low/OK;线程栈采样发现大量阻塞在
buffer.request() -
Reactor / WebFlux:订阅者调用
request(n)控制拉取节奏;若忽略 request、盲目onBackpressureBuffer(),易 OOM -
Node.js Stream:
Writable.write()返回false表示内部缓冲已满,此时应暂停Readable的push() -
Kafka Consumer:poll() 后未及时处理,导致 fetch buffer 积压,触发
max.poll.interval.ms超时而被踢出 Group
应对思路不是消灭背压,而是管理它
健康的背压是可控的、短暂的;持续高背压才需干预:
- 先定位瓶颈:从 Sink 往 Source 反向查,找到第一个显示 HIGH 的 Task 或 Operator
- 看指标:检查该节点的 CPU、GC、网络写入耗时、state 访问延迟等基础资源
- 调配置:增加并行度、调大 network buffers、启用 Unaligned Checkpoint、限制 source rate
- 改逻辑:规避全量 broadcast、优化 UDF、拆分重逻辑、加异步非阻塞调用

















