天天看點

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

​​簡介​​

​​http2中的流控制​​

​​netty對http2流控制的封裝​​

http2flowcontroller

http2localflowcontroller

http2remoteflowcontroller

​​流控制的使用​​

​​總結​​

簡介

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流控制的封裝

從上面的介紹我們知道,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的大小。

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

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大小。

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實作中應該會遇到。

繼續閱讀