netty系列之:netty實現http2中的流控制


簡介

HTTP2相對於http1.1來說一個重要的提升就是流控制flowcontrol。為什么會有流控制呢?這是因為不管是哪種協議,客戶端和服務器端在接收數據的時候都有一個緩沖區來臨時存儲暫時處理不了的數據,但是緩沖區的大小是有限制的,所以有可能會出現緩沖區溢出的情況,比如客戶端向服務器端上傳一個大的圖片,就有可能導致服務器端的緩沖區溢出,從而導致一些額外的數據包丟失。

為了避免緩沖區溢出,各個HTTP協議都提供了一定的解決辦法。

在HTTP1.1中,流量的控制依賴的是底層TCP協議,在客戶端和服務器端建立連接的時候,會使用系統默認的設置來建立緩沖區。在數據進行通信的時候,會告訴對方它的接收窗口的大小,這個接收窗口就是緩沖區中剩余的可用空間。如果接收窗口大小為零,則說明接收方緩沖區已滿,則發送方將不再發送數據,直到客戶端清除其內部緩沖區,然后請求恢復數據傳輸。

HTTP2通過客戶端和服務器端的應用中進行緩沖區大小消息的傳輸,通過在應用層層面控制數據流,所以各個應用端可以自行控制流量的大小,從而實現更高的連接效率。

本文將會介紹netty對http2流控制的支持。

http2中的流控制

在簡介中我們也提到了,傳統的HTTP1.1使用的是系統底層的流量控制機制,具體來說就是TCP的流控制。但是TCP的流控制在HTTP2中就不夠用了。因為HTTP2使用的是多路復用的機制,一個TCP連接可以有多個http2連接。所以對http2來說TCP本身的流控制機制太粗糙了,不夠精細。

所以在HTTP2中,實現了更加精細的流控制機制,它允許客戶端和服務器實現其自己的數據流和連接級流控制。

具體的流程是這樣的,當客戶端和服務器端建立連接之后,會發送Http2SettingsFrame,這個settings frame中包含了SETTINGS_INITIAL_WINDOW_SIZE,這個是發送端的窗口大小,用於 Stream 級別流控。流控制窗口的默認值設為65,535字節,但是接收方可以對其進行修改,最大值為2^31-1 字節。

建立好初始windows size之后,對於接收方來說,每次發送方發送data frame就會減少window的的大小,而接收方每次發送WINDOW_UPDATE frame時候就會增加window的大小,從達到動態控制的目的。

netty對http2流控制的封裝

Http2FlowController

從上面的介紹我們知道,http2對流控制是通過兩個方面來實施的,第一個方面就是初始化的Http2SettingsFrame,通過設置SETTINGS_INITIAL_WINDOW_SIZE來控制初始window的大小。第二個方面就是在后續的WINDOW_UPDATE frame中對window的大小進行動態增減。

對於netty來說,這一切都是封裝在Http2FlowController類中的。Http2FlowController是一個抽象類,它有兩個實現,分別是Http2LocalFlowController和Http2RemoteFlowController。他們分別表示對inbound flow of DATA 和 outbound flow of DATA的處理。

Http2FlowController中主要有5個方法,分別是:

  • set channelHandlerContext:綁定flowcontrol到ChannelHandlerContext上。
  • set initialWindowSize:初始化window size,等同於設置SETTINGS_INITIAL_WINDOW_SIZE。
  • get initialWindowSize: 返回初始化window size。
  • windowSize: 獲取當前的windowSize。
  • incrementWindowSize: 增加flow control window的大小。

接下來我們看下他的兩個實現類,有什么不一樣的地方。

Http2LocalFlowController

LocalFlowController用來對遠程節點發過來的DATA frames做flow control。它有5個主要的方法。

  • set frameWriter: 用來設置發送WINDOW_UPDATE frames的frame writer。
  • receiveFlowControlledFrame: 接收inbound DATA frame,並且對其進行flow control。
  • consumeBytes: 表示應用已經消費了一定數目的bytes,可以接受更多從遠程節點發過來的數據。flow control可以發送 WINDOW_UPDATE frame來重置window大小。
  • unconsumedBytes: 接收到,但是未消費的bytes。
  • initialWindowSize: 給定stream的初始window大小。

Http2RemoteFlowController

remoteFlowController用來處理發送給遠程節點的outbound DATA frames。它提供了8個方法:

  • get channelHandlerContext: 獲取當前flow control的context.
  • addFlowControlled: 將flow control payload添加到發送到遠程節點的queue中。
  • hasFlowControlled: 判斷當前stream是否有 FlowControlled frames在queue中。
  • writePendingBytes: 將流量控制器中的所有待處理數據寫入流量控制限制。
  • listener: 給 flow-controller添加listener。
  • isWritable: 確定流是否有剩余字節可用於流控制窗口。
  • channelWritabilityChanged: context的writable狀態是否變化。
  • updateDependencyTree: 更新stream之間的依賴關系,因為stream是可以有父子結構的。

流控制的使用

flowControl相關的類主要被用在Http2Connection,Http2ConnectionDecoder,Http2ConnectionEncoder中,在建立http2連接的時候起到相應的作用。

總結

flowControl是http2中的一個比較底層的概念,大家在深入了解netty的http2實現中應該會遇到。

本文已收錄於 http://www.flydean.com/29-netty-flowcontrol/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM