一圖道盡心酸:
大的原理,上游的task產生數據后,會寫在本地的緩存中,然后通知JM自己的數據已經好了,JM通知下游的Task去拉取數據,下游的Task然后去上游的Task拉取數據,形成鏈條。
但是在何時通知JM?這里有一個設置,比如pipeline還是blocking,pipeline意味着上游哪怕產生一個數據,也會去通知,blocking則需要緩存的插槽存滿了才會去通知,默認是pipeline。
雖然生產數據的是Task,但是一個TaskManager中的所有Task共享一個NetworkEnvironment,下游的Task利用ResultPartitionManager主動去上游Task拉數據,底層利用的是Netty和TCP實現網絡鏈路的傳輸。
那么,一直都在說Flink的背壓是一種自然的方式,為什么是自然的了?
從上面的圖中下面的鏈路中可以看到,當下游的process邏輯比較慢,無法及時處理數據時,他自己的local buffer中的消息就不能及時被消費,進而導致netty無法把數據放入local buffer,進而netty也不會去socket上讀取新到達的數據,進而在tcp機制中,tcp也不會從上游的socket去讀取新的數據,上游的netty也是一樣的邏輯,它無法發送數據,也就不能從上游的localbuffer中消費數據,所以上游的localbuffer可能就是滿的,上游的operator或者process在處理數據之后進行collect.out的時候申請不能本地緩存,導致上游的process被阻塞。這樣,在這個鏈路上,就實現了背壓。
如果還有相應的上游,則會一直反壓上去,一直影響到source,導致source也放慢從外部消息源讀取消息的速度。一旦瓶頸解除,網絡鏈路暢通,則背壓也會自然而然的解除。