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

2022-12-30 12:01:06

作者:顧欣

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)通知使用者端更新視窗。使用者端收到視窗更新包後就會增加對應值的流控視窗,從而達到動態控制的目的。

二、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、Inbound流控

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

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

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

3) 更新流控視窗

4) 傳送流控更新封包(window_update)

3、Outbound流控

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

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

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

3) 反饋使用者端流控異常

4、總結

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

三、未來展望

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

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