Flink 内部是基于producer-consumer模型来进行消息传递的,Flink的反压设计也是基于这个模型。
Flink 使用了高效有界的分布式阻塞队列,就像 Java 通用的阻塞队列(BlockingQueue)一样。
下游消费者消费变慢,上游就会受到阻塞。
- Flink 1.5 之前的版本并没有对反压做特别的处理,它利用buffer来暂存堆积的无法处理的数据,当 buffer 用满了,则上游的流阻塞,不再发送数据。可见此时的反压是从下游往上游传播的,一直往上传播到 Source Task 后,Source Task最终会降低或提升从外部Source 端读取数据的速率。
这种机制有一个比较大的问题,在这样的一个场景下:同一 Task的不同 SubTask 被安排到同一个 TaskManager,则SubTask与其他TaskManager 的网络连接将被多路复用并共享一个 TCP信道以减少资源使用,所以某个 SubTask产生了反压的话会把多路复用的TCP通道占住,从而会把其他复用同一 TCP信道的且没有流量压力的SubTask阻塞。
- Flink1.5版本之后的基于Credit反压机制解决了上述问题。
这种机制主要是每次上游SubTask给下游SubTask发送数据时,会把Buffer中的数据和上游ResultSubPartition堆积的数据量Backlog size发给下游,下游会接收上游发来的数据,并向上游反馈目前下游现在的Credit值,Credit值表示目前下游可以接收上游的Buffer量,1个Buffer等价于1个Credit。
可见,这种策略上游向下游发送数据是按需发送的,而不是和之前一样会在公用的Netty和TCP这一层数据堆积,避免了影响其他SubTask通信的问题。