反压(反压力)是实时计算应用开发中,特别是流式计算中,十分常见的问题。反压意味着数据管道中某个节点成为瓶颈,处理速率跟不上上游发送数据的速率,而需要对上游进行限速。由于实时计算应用通常使用消息队列来进行生产端和消费端的解耦,消费端数据源是基于拉的,所以反压通常是从某个节点传导至数据源并降低数据源(比如卡夫卡消费者)的摄入速率。
关于Flink的反压机制,网上已经有不少博客介绍,中文博客推荐这两篇1。简单来说,Flink拓扑中每个节点(任务)间的数据都以阻塞队列的方式传输,下游来不及消费导致队列被占满后,上游的生产也会被阻塞,最终导致数据源的摄入被阻塞。而本文将着重结合官方的博客[4]分享笔者在实践中分析和处理Flink反压的经验。
图1. Flink 1.8的Web UI反压面板(来自官方博客) 如果处于反压状态,那么有两种可能性:
反压的影响
反压并不会直接影响作业的可用性,它表明作业处于亚健康的状态,有潜在的性能瓶颈并可能导致更大的数据处理延迟。通常来说,对于一些对延迟要求不太高或者数据量比较小的应用来说,反压的影响可能并不明显,然而对于规模比较大的Flink作业来说反压可能会导致严重的问题。 这是因为Flink的检查点机制,反压还会影响到两项指标:检查点时长和国家大小。-
<李类=" Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-reset public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
前者是因为检查点的障碍是不会越过普通数据的,数据处理被阻塞也会导致检查点障碍流经整个数据管道的时长变长,因而检查点总体时间(端到端)持续时间变长。李>
<李类=" Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
后者是因为为保证EOS (Exactly-Once-Semantics,准确一次),对于有两个以上输入管道的运营商,检查点障碍需要对齐(对齐),接受到较快的输入管道的障碍后,它后面数据会被缓存起来但不处理,直到较慢的输入管道的障碍也到达,这些被缓存的数据会被放到国家里面,导致检查点变大。李>
定位反压节点
要解决反压首先要做的是定位到造成反压的节点,这主要有两种办法:-
<李类=" Editable-styled public-DraftStyleDefault-orderedListItem public-DraftStyleDefault-reset public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
通过Flink Web UI自带的反压监控面板;李>
<李类=" Editable-styled public-DraftStyleDefault-orderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
通过Flink任务指标。李>
反压监控面板
Flink Web UI的反压监控提供了子任务级别的反压监控,原理是通过周期性对任务线程的栈信息采样,得到线程被阻塞在请求缓冲区(意味着被下游队列阻塞)的频率来判断该节点是否处于反压状态。默认配置下,这个频率在0.1以下则为好,0.1至0.5为低,而超过0.5则为高。图1. Flink 1.8的Web UI反压面板(来自官方博客) 如果处于反压状态,那么有两种可能性:
-
<李类=" Editable-styled public-DraftStyleDefault-orderedListItem public-DraftStyleDefault-reset public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
该节点的发送速率跟不上它的产生数据速率。这一般会发生在一条输入多条输出的运营商(比如flatmap)。李>
<李类=" Editable-styled public-DraftStyleDefault-orderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR”>
下游的节点接受速率较慢,通过反压机制限制了该节点的发送速率。