Dubbo 3 之 Triple 流控反壓原理解析

ApacheDubbo發表於2022-12-30

作者:顧欣

Triple 是 Dubbo 3 提出的基於 HTTP2 的開放協議,旨在解決 Dubbo 2 私有協議帶來的互通性問題。Triple 基於 HTTP/2 定製自己的流控,支援透過特定的異常通知客戶端業務層服務端負載高情況,保護了服務端被大流量擊垮,提高系統高可用能力。

一、流控反壓現狀

客戶端和伺服器端在接收資料的時候有一個緩衝區來臨時儲存資料,但是緩衝區的大小是有限制的,所以有可能會出現緩衝區溢位的情況,HTTP 透過流控保護資料溢位丟失風險。

1、HTTP/1 流控

在 HTTP/1.1 中,流量的控制依賴的是底層TCP協議,在客戶端和伺服器端建立連線的時候,會使用系統預設的設定來建立緩衝區。在資料進行通訊的時候,會告訴對方它的接收視窗的大小,這個接收視窗就是緩衝區中剩餘的可用空間。如果接收視窗大小為零,則說明接收方緩衝區已滿,則傳送方將不再傳送資料,直到客戶端清除其內部緩衝區,然後請求恢復資料傳輸。

2、HTTP/2 流控

HTTP/2 使用了多路複用機制,一個TCP連線可以有多個 HTTP/2 連線,故在 HTTP/2 中,有更加精細的流控制機制,允許服務端實現自己資料流和連線級的流控制。服務端與客戶端初次見了連線時,會透過傳送 HTTP/2 SettingsFrame設定初始化的流控視窗大小,用於 Stream 級別流控,預設為 65,535 位元組。定好流控視窗後,每次客戶端傳送資料就會減少流控視窗的大小,服務端收到資料後會傳送視窗更新包(WINDOW_UPDATE frame)通知客戶端更新視窗。客戶端收到視窗更新包後就會增加對應值的流控視窗,從而達到動態控制的目的。

1.png

二、Triple流控反壓

Netty 基於 HTTP/2 實現了基礎的流控,當服務端負載過高,客戶端傳送視窗為 0 時,新增請求就無法被髮送出去,會在快取到客戶端待傳送請求佇列中,快取資料過大,就會造成客戶端記憶體溢位,影響業務程式。

Triple 基於 Netty 實現了 HTTP/2 協議,透過 HTTP/2 FlowController介面統一封裝,在實現分為進站(inbound)和出站(outbound)兩個維度的實現。Triple 在 inbound 流量上使用了 Netty 的預設流控實現,在 outbound 上實現了自己流控,基於服務端負載,將服務端流量壓力透傳到客戶端業務層,實現客戶端的業務反壓,暫停業務繼續傳送請求,保護服務端不被大流量擊垮。

1、連線初始化

Triple在初次建立連線時,透過 TripleHttpProtocol 初始化 HTTP/2 配置,預設流控視窗 DEFAULT_WINDOW_INIT_SIZE = MIB_8,並在服務端和客戶端加入自己的 outbound 流控介面。

2.png

2、Inbound流控

Inbound 流量會透過 DefaultHttpLocalFlowControllerconsumeBytes 方法實現流控視窗更新與傳送。

1) 入口傳入HTTP 流與更新資料大小

3.png

2) 找到對應連線實現資料消費

4.png

3) 更新流控視窗

5.png

4) 傳送流控更新資料包(window_update)

6.png

3、Outbound流控

Outbound 透過 Triple 自己的流控實現 TriHttpRemoteFlowController,將服務端壓力反饋到業務層,保護服務端被大流量擊垮。

1) 傳送資料時判斷是否還有視窗

7.png

2) 視窗為0時丟擲特定異常

8.png

3) 反饋客戶端流控異常

9.png

4、總結

Triple 透過將底層客戶端傳送視窗為 0 場景封裝為特定流控異常,透傳至客戶端上層業務,阻止客戶端業務繼續資料傳送,有效的保護了服務端被大流量擊垮和客戶端的記憶體溢位的問題。

三、未來展望

目前 Triple 已經基本實現了流控反壓能力,未來我們將深度聯動業務,基於業務負載自適應調整反壓流控,一是在 inbound 上將流控視窗包傳送時機調整到服務端業務處理完成後,二是在 outbound 流量上關聯客戶端業務層,動態調整客戶端傳送速率。從而實現基於服務端業務負載動態反壓流控機制。

歡迎在 https://github.com/apache/dubbo 給 Dubbo Star。

相關文章