Flink初探之 动态限流

前言

最近一段时间,接触到公司flink代码,修改时遇到一个flink常见问题,就是上游Producer生产数据的效率大于下游Consumer的消费速度,所以查阅一些大佬的资料,将这一问题记录,后续系统学习flink的时候复习一下

Flink 流处理为什么需要网络流控?

分析一个简单的 Flink 流任务,下图是一个简单的Flink流任务执行图:任务首先从 Kafka 中读取数据、 map 算子对数据进行转换、keyBy 按照指定 key 对数据进行分区(相同 key 的数据经过 keyBy 后分到同一个 subtask 实例中),keyBy 后对数据接着进行 map 转换,然后使用 Sink 将数据输出到外部存储。
Flink初探之 动态限流_第1张图片
在大数据处理中,无论是批处理还是流处理,单点处理的性能总是有限的,我们的单个 Job 一般会运行在多个节点上,多个节点共同配合来提升整个系统的处理性能。图中,任务被切分成 4 个可独立执行的 subtask( A0、A1、B0、B1),在数据处理过程中,就会存在 shuffle(数据传输)的过程。例如,subtask A0 处理完的数据经过 keyBy 后发送到 subtask B0、B1 所在节点去处理。
那么问题来了,下图中,上游 Producer 向下游 Consumer 发送数据,在发送端和接受端都有相应的 Send Buffer 和 Receive Buffer,但是上游 Producer 生成数据的速率比下游 Consumer 消费数据的速率快。Producer 生产数据 2MB/s, Consumer 消费数据 1MB/s,Receive Buffer 只有 5MB,所以过了5秒后,接收端的 Receive Buffer 满了。(可以把下图中的 Producer 当做上面案例中的 subtask A0,把下图中的 Consumer 当做上面案例中的 subtask B0)
Flink初探之 动态限流_第2张图片
下游接收区的 Receive Buffer 有限,如果上游一直有源源不断的数据,那么将会面临着以下两个情况:

  1. 下游消费者会丢弃新到达的数据,因为下游消费者的缓冲区放不下
  2. 为了不丢弃数据,所以下游消费者的 Receive Buffer 持续扩张,最后耗尽消费者的内存,OOM,程序挂掉

这两种情况在生产环境都是不能接受的,第一种会把数据丢弃、第二种会把我们的应用程序挂掉。所以,该问题的解决方案不应该是下游 Receive Buffer 一直累积数据,而是上游 Producer 发现下游 Consumer 处理比较慢之后,应该在 Producer 端做出限流的策略,防止在下游 Consumer 端无限制的数据堆积。

那上游 Producer 端该如何做限流呢?可以采用下图所示静态限流的策略:
Flink初探之 动态限流_第3张图片
下游 Consumer 端会频繁地向上游 Producer 端进行动态反馈,告诉 Producer 下游 Consumer 的负载能力,从而 Producer 端动态调整向下游 Consumer 发送数据的速率实现 Producer 端的动态限流。当 Consumer 端处理较慢时,Consumer 将负载反馈到 Producer 端,Producer端会根据反馈适当降低 Producer 自身从上游或者 Source 端读数据的速率来降低向下游 Consumer 发送数据的速率。当 Consumer 处理负载能力提升后,又及时向 Producer 端反馈,Producer 会通过提升从上游或 Source 端读数据的速率来提升向下游发送数据的速率。通过这个动态反馈来提升整个系统的吞吐量。

补充一点,如下图所示,假如我们的 Job 分为 Task A、B、C,Task A 是 Source Task、Task B 处理数据、Task C 是 Sink Task。假如 Task C 由于各种原因吞吐量降低,会将负载信息反馈给 Task B,Task B 会降低向 Task C 发送数据的速率,此时如果 Task B 如果还是一直从 Task A 读取数据,那么按照同样的道理,数据会把 Task B 的 Send Buffer 和 Receive Buffer 撑爆,又会出现上面描述的问题。所以,当 Task B 的 Send Buffer 和 Receive Buffer 被用完后,Task B 会用同样的原理将负载信息反馈给 Task A,Task A 收到 Task B 的负载信息后,会降低 给 Task B 发送数据的速率,以此类推。
Flink初探之 动态限流_第4张图片
上面这个流程,就是 Flink 动态限流(反压机制)的简单描述。我们可以看到 Flink 的反压其实是从下游往上游传播的,一直往上传播到 Source Task 后,Source Task 最终会降低从 Source 端读取数据的速率。如果下游 Task C 的负载能力提升后,会及时反馈给 Task B,于是 Task B 会提升往 Task C 发送数据的速率,Task B 又将负载提升的信息反馈给 Task A,Task A 就会提升从 Source 端读取数据的速率,从而提升整个系统的负载能力。

转载自: 一文搞懂 Flink 网络流控与反压机制.

你可能感兴趣的:(大数据)