Flink 內部是基于producer-consumer模型來進行消息傳遞的,F(xiàn)link的反壓設計也是基于這個模型。
Flink 使用了高效有界的分布式阻塞隊列,就像 Java 通用的阻塞隊列(BlockingQueue)一樣。
下游消費者消費變慢,上游就會受到阻塞。
- Flink 1.5 之前的版本并沒有對反壓做特別的處理,它利用buffer來暫存堆積的無法處理的數(shù)據(jù),當 buffer 用滿了,則上游的流阻塞,不再發(fā)送數(shù)據(jù)??梢姶藭r的反壓是從下游往上游傳播的,一直往上傳播到 Source Task 后,Source Task最終會降低或提升從外部Source 端讀取數(shù)據(jù)的速率。
這種機制有一個比較大的問題,在這樣的一個場景下:同一 Task的不同 SubTask 被安排到同一個 TaskManager,則SubTask與其他TaskManager 的網(wǎng)絡連接將被多路復用并共享一個 TCP信道以減少資源使用,所以某個 SubTask產生了反壓的話會把多路復用的TCP通道占住,從而會把其他復用同一 TCP信道的且沒有流量壓力的SubTask阻塞。
- Flink1.5版本之后的基于Credit反壓機制解決了上述問題。
這種機制主要是每次上游SubTask給下游SubTask發(fā)送數(shù)據(jù)時,會把Buffer中的數(shù)據(jù)和上游ResultSubPartition堆積的數(shù)據(jù)量Backlog size發(fā)給下游,下游會接收上游發(fā)來的數(shù)據(jù),并向上游反饋目前下游現(xiàn)在的Credit值,Credit值表示目前下游可以接收上游的Buffer量,1個Buffer等價于1個Credit。
可見,這種策略上游向下游發(fā)送數(shù)據(jù)是按需發(fā)送的,而不是和之前一樣會在公用的Netty和TCP這一層數(shù)據(jù)堆積,避免了影響其他SubTask通信的問題。