Flink 內部是基于producer-consumer模型來進(jin)行(xing)消(xiao)息傳遞的,Flink的反壓設計也是基于這個模型。
Flink 使用了高效有界的(de)分布式阻塞隊列(lie),就像 Java 通用的(de)阻塞隊列(lie)(BlockingQueue)一(yi)樣。
下游消費(fei)者(zhe)消費(fei)變慢,上游就會受到阻塞。
- Flink 1.5 之前(qian)的(de)版本并(bing)沒有(you)對反(fan)壓(ya)做特別的(de)處理(li),它(ta)利用buffer來暫存(cun)堆積的(de)無法處理(li)的(de)數據,當(dang) buffer 用滿了,則上游的(de)流(liu)阻塞,不再發送數據。可見此時的(de)反(fan)壓(ya)是從(cong)下游往(wang)(wang)上游傳播的(de),一直往(wang)(wang)上傳播到 Source Task 后,Source Task最終會降低或(huo)提升從(cong)外部Source 端(duan)讀取數據的(de)速率。
這(zhe)種機制有(you)一(yi)(yi)(yi)個(ge)(ge)比較(jiao)大的(de)問題,在這(zhe)樣的(de)一(yi)(yi)(yi)個(ge)(ge)場景下:同一(yi)(yi)(yi) Task的(de)不(bu)同 SubTask 被安排到同一(yi)(yi)(yi)個(ge)(ge) TaskManager,則(ze)SubTask與其他TaskManager 的(de)網絡(luo)連(lian)接(jie)將(jiang)被多路(lu)復用并共享(xiang)一(yi)(yi)(yi)個(ge)(ge) TCP信道以減少資源使用,所以某個(ge)(ge) SubTask產生(sheng)了(le)反壓的(de)話(hua)會把(ba)多路(lu)復用的(de)TCP通道占住,從而會把(ba)其他復用同一(yi)(yi)(yi) TCP信道的(de)且沒有(you)流量壓力的(de)SubTask阻塞。
- Flink1.5版本之后的(de)基于(yu)Credit反壓機制解(jie)決(jue)了上述(shu)問題(ti)。
這(zhe)種機制主要是(shi)每(mei)次上游(you)(you)(you)SubTask給(gei)下(xia)游(you)(you)(you)SubTask發(fa)送數(shu)據(ju)時,會把Buffer中的(de)數(shu)據(ju)和上游(you)(you)(you)ResultSubPartition堆積的(de)數(shu)據(ju)量(liang)Backlog size發(fa)給(gei)下(xia)游(you)(you)(you),下(xia)游(you)(you)(you)會接(jie)收(shou)上游(you)(you)(you)發(fa)來的(de)數(shu)據(ju),并向上游(you)(you)(you)反饋目(mu)(mu)前下(xia)游(you)(you)(you)現在的(de)Credit值,Credit值表示目(mu)(mu)前下(xia)游(you)(you)(you)可以接(jie)收(shou)上游(you)(you)(you)的(de)Buffer量(liang),1個(ge)Buffer等(deng)價于1個(ge)Credit。
可見,這種策略上游(you)向(xiang)下(xia)游(you)發送數據(ju)是按需發送的,而不(bu)是和之前一樣會在公用(yong)的Netty和TCP這一層數據(ju)堆積,避免了影響其他SubTask通信的問題。