在实时数据处理场景中,Apache Flink 凭借其高吞吐、低延迟的特性成为流式计算的首选框架。然而,许多开发者都遇到过这样的问题:Flink作业突然变慢,数据处理延迟飙升,甚至任务频繁失败等情况——这很可能是反压(Backpressure)在作祟!
本文将从反压原理出发,结合案例,分享如何排查和优化的策略。
在 Apache Flink 中,反压(Backpressure) 是一种流量控制机制,用于解决数据流处理中生产者(上游任务)速度超过消费者(下游任务)处理能力的问题。当系统出现反压时,Flink 会自动调整数据流动,避免下游任务因过载而崩溃或产生高延迟。
·正面作用: 防止系统因过载崩溃,保障稳定性。
·负面作用:可能导致任务不稳定, 出现吞吐量下降、延迟增加,作业停滞,发生failover, OOM等情况。
当出现反压的时候, 如果任务稳定, 并且数据时效性在业务的容忍范围内可以不做处理。因为反压造成频繁failover 、数据时效性降低、长时间的数据滞留(滞留时间越长,恢复成本就越高)等负面情况, 影响业务的正常运转就需要处理。
反压的本质是数据生产速度 > 数据消费速度,导致下游任务无法及时处理上游发送的数据,进而引发数据积压。具体场景包括:
·计算密集型算子(如窗口聚合、复杂 UDF)处理速度慢。
·外部系统瓶颈(如数据库、消息队列 Sink 写入慢)。
·数据倾斜(某些子任务处理的数据量远高于其他子任务)。
·资源不足(CPU、内存、网络带宽受限)。
Flink 通过基于信用(Credit-Based)的流量控制实现反压。
信用(Credit):下游任务会向上游任务声明自己还能接收多少数据(类似 TCP 滑动窗口)。初始信用值由下游任务的空闲缓冲区大小决定。每处理完一批数据,下游会向上游发送新的信用值。
上游任务仅在下游有足够信用时发送数据。
若下游信用耗尽(Credit = 0),上游暂停发送,触发反压。
关键步骤解析
1.信用初始化
下游Task启动时向上游申请初始信用(如10个Buffer配额)。
2.数据发送阶段
上游每发送1个数据包占用1个Buffer,信用值减1。
下游消费后通过ACK消息返还信用(每消费1个Buffer返还1信用)。
3.反压触发条件
当下游处理变慢→信用耗尽(Credit=0)→上游停止发送数据。
下游通过BackPressureSample线程检测堆栈是否阻塞,确认反压状态。
4.恢复机制
下游处理能力恢复后,主动推送新信用值到上游,重新激活数据流。
反压如何从下游向上游传播?
反压会从最慢的算子(瓶颈点)向源头(Source)逐级反向传播:
1.Sink 算子写入慢(如数据库延迟)→ 积压数据。
2.下游算子处理慢(如窗口聚合)→ 输入缓冲区填满。
3.上游任务检测到下游无信用→ 停止发送数据。
4.最终 Source 降低数据摄入速率(如 Kafka Consumer 暂停拉取消息)。
Flink Web 界面提供了一个选项卡来监控正在运行 jobs 的反压行为。
WebUI 集合了所有 subTasks 的反压和繁忙指标的最大值,并在 JobGraph 中将集合的值进行显示。除了显示原始的数值,tasks 也用颜色进行了标记,使检查更加容易。
闲置的 tasks 为蓝色,完全被反压的 tasks 为黑色,完全繁忙的 tasks 被标记为红色。 中间的所有值都表示为这三种颜色之间的过渡色。
在 Job Overview 旁的 Back Pressure 选项卡中,你可以找到更多细节指标。
如果你看到 subtasks 的状态为 OK 表示没有反压。HIGH 表示这个 subtask 被反压。状态用如下定义:
·OK: 0% <= 反压比例 <= 10%
·LOW: 10% < 反压比例 <= 50%
·HIGH: 50% < 反压比例 <= 100%
除此之外,你还可以找到每一个 subtask 被反压、闲置或是繁忙的时间百分比。
Flink 提供了一些内置的metric指标用于监控任务的反压信息。
关键指标:inPoolUsage、outPoolUsage、isBackPressured 、latency。
由于实时任务的特殊性, 任务时启动正常之后, 一般都是7*24h运行, 一般要满足以下场景。
·要可以实时查看任务状态, 当任务异常可以通过监控页面辅助排查, 提升定位问题的效率。
·要支持不同的告警规则, 根据任务的优先级可以配置不同的告警策略。当任务异常时可以主动感知, 而不是下游用户或者数据不准确的时候被动感知。
下面排列几种常见的原因。
|
资源不足 |
CPU资源不足 |
算子处理逻辑复杂或计算密集型操作导致CPU满载 |
||
|
内存不足 |
状态过大或窗口操作消耗过多内存 |
|||
|
网络带宽不足 |
节点间数据传输量超过网络容量 |
|||
|
并行度设置不合理 |
并行度过低无法处理输入数据速率 |
|||
|
数据倾斜 |
Key分布不均 |
某些Key的数据量远大于其他Key |
||
|
分区策略不合理 |
导致某些TaskManager负载过高 |
|||
|
外部系统瓶颈 |
Sink吞吐量不足 |
如数据库、消息队列等外部系统写入速度慢 |
||
|
Source读取速度不稳定 |
如Kafka分区分配不均或消费延迟 |
|||
|
算子性能问题 |
状态操作低效 |
频繁的状态访问或大状态操作 |
||
|
复杂计算逻辑 |
如正则匹配、复杂聚合等耗时操作 |
|||
|
同步外部调用 |
在算子内进行同步的RPC或数据库调用 |
|||
|
配置问题 |
缓冲区大小不足 |
网络缓冲区或任务管理器内存配置过小 |
||
|
检查点配置不当 |
检查点间隔过短或状态过大导致频繁反压 |
|||
|
序列化/ 反序列化开销大 |
使用低效的序列化方式 |
|||
|
系统设计问题 |
流水线设计不合理 |
算子间处理能力不匹配 |
||
|
缺乏反压处理机制 |
未实现适当的反压策略 |
|||
现象: flink任务出现数据滞留、 出现反压情况。
排查步骤:
1. 收到Flink任务异常报警之后,一般首先查看监控页面,观察任务的运行情况,通过观察发现GC指标无明显异常, 但是有数据滞留量增多, 反压的情况。
2. 查看Flink UI页面, 发现有反压的情况, 任务日志无报错信息。查看Flink UI页面如下图。发现最后一个算子处于busy状态, 第一个算子有反压异常。
因为flink会对任务做优化, 将多个算子合并成一个。我们只能看到某一段代码有问题, 无法精确定位是哪个算子。
3. 可以临时增加参数, 关闭Flink的算子优化,不同Flink版本的参数有差异,当前任务的版本为Flink1.14,参数为:"pipeline.opreator-chaining=false",增加参数重新启动Flink任务,再次查看Flink UI页面。
Flink1.18版本参数为:"pipeline.operator-chaining.enabled=false"
·window算子处于busy状态, 是性能瓶颈点。但是没有反压。
·下游算子空闲, 无反压。
·window算子前面的算子都处于反压状态且空闲程度较高。 window 算子处于性能瓶颈。
·反压会依次向上传递, 可以看到Source算子也处于反压状态。
4. 查看任务的监控页面, 确认数据量有无激增的情况, taskmanager和 jobmanager有没有GC。
5. 查看任务的历史执行记录, 任务没有更新操作, 无gc . 考虑是数据增多导致数据发生滞留, 当前任务的并行度是1, 无GC的情况, 通过提高并行度解决。
6. 增加并行度之后, 观察任务正常恢复。关闭调试参数: "pipeline.operator-chaining=true"。
Flink 反压(Backpressure)是流处理系统中常见的问题,当数据处理速度跟不上数据产生速度时就会发生。
本文主要简单讲述了Flink 反压的原理以及反压的排查流程。
主要的处理方式如下:
·数据倾斜优化
rebalance() 重分布数据
热点Key单独处理(如加盐、本地聚合)
·资源调优
调整并行度(增加或重新分配)
优化TaskManager内存配置(堆内存、网络缓冲区)
·代码优化
减少状态访问(如使用ValueState优化)
异步I/O(避免阻塞Sink写入)
·外部系统优化
批处理写入(调整batch.size和flush.interval)
增加Sink端并行度(如Kafka分区数)
·配置调优
调整检查点参数(间隔、超时时间)
优化反压采样频率
(web.backpressure.refresh-interval)
·参考链接
https://nightlies.apache.org/flink/flink-docs-release-2.1/docs/ops/monitoring/back_pressure/
https://nightlies.apache.org/flink/flink-docs-release-2.1/docs/deployment/metric_reporters/

