HTTP2 學習


一、HTTP1.x存在的問題

      Http1.0時Connection無法復用,同一時間一個Connection只能處理一個request。Http1.1引入了Request pipelining來解決這一問題,Request pipelining。

  Requestpipeling在FIFO基礎上支持同一Connection並發處理多個Request,這里的FIFO是指Http Response發送順序必須與Request的發送順序保持一致。
  詳情前往https://en.wikipedia.org/wiki/HTTP_pipelining

  然而它並不完美,仍然有HOL Blocking問題。

     

  所謂的行首阻塞是因於FIFO的原因,導致后面的Reponse由於其之前的Response由於資源搶占等原因無法輸出而Block。

  由於這樣的限制,HTTP/1.0及HTTP/1.1時代需要對Server端創建多個連接,通過提高並發度來降低Latency。

  另外Http2支持Header壓縮,而Header壓縮在此前是不支持的,此前一般是對body進行gzip壓縮。

 

二、HTTP2的解決方案

  HTTP2在協議上真正要求不同的Request可以在同一個Connection上交錯進行,真正做到多路復用。所帶來的好處顯而易見,更少的Connection,更好的並發,更高效的網絡資源利用。

  支持流量控制及請求優先級,使得重要的請求優先得到處理,這一點對於應用來說是個大的優化點,以體驗為目標,對不同的請求划分優先級以及流量控制,比如異步加載的內容重要性低,可以設置較低優先級。但是個人覺得這一點要做好很難,要依賴於瀏覽器,應用服務器,應用程序三個地方都有非常好的實現,是否是合理的實現還需要好的度量平台,視效果而定。

  Server Push機制支持Server端應用程序可以預先輸出內容暫未需要的內容,從而降低潛在的延時。舉例:可以把css內容與html內容同步輸出,而不需要等待html完全輸出后,瀏覽器再加載css。

  支持對Http Header進行壓縮。

  高效的二進制格式(相對文本格式)傳輸。

三、原理分析

   

  將通過Jetty源碼來分析Jetty如何支持Http2的
  Jetty源碼地址:git://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git

  A. Jetty.io&Jetty.server主要類結構圖:

Jetty.io主要是對EndPoint及Connection的定義和基本實現,Jetty.server實現了絡的交互過程,包裝了Socket,Channel,多路復用等實現。這兩個包一起對應用程序端或協議格式端提供了網絡交互過程,從而實現網絡交互過程對於協議及應用的透明。

B. 與Http2協議的結合:

  Jetty Basic如上圖已經介紹,HTTP2的實現只擴展ServerConnection,ServerConnectionFactory即可,相當於Jetty內核上增加插件,擴展性好,另外也不需要關注網絡細節

C. 對重點類的重點解讀:

 

類名 職責 詳細介紹
HTTP2Flusher Frame輸出控制類 重點說明:
HTTP2Flusher類中保存了各種Entry隊列,Entry中包含Frame數據,其對應的Stream引用,以及對應的CallBack。
主要屬性: 
Queue<WindowEntry> windows,WindowUpdateFrame類型的保存隊列
ArrayQueue<Entry> frames,Frame數據隊列 
主要方法:
window(), prepend(), append(), remove()等都是針對如上Queue的操作
process()真正執行Frame的輸出。首先執行Window隊列,將Window的窗口設置數據寫入到對應的Stream或Session中;然后執行WindowsSize的限流邏輯,若對應的Session或Stream當前WindowSize不大於0,則不發送Frame,否則將WindowSize減去當前Frame的Size,應用於下次限流。最后調用Session中的EndPoint類的write方法將Frame輸出
FlowControlStrategy 流控接口定義 重點說明: 
其實現類主要實現了依據發送或接收的Frame的數據length,依據固定策略改寫Session及Stream的WindowSize,以及Stream另一端EndPoint對於WindowSize的要求,完成輸科和輸出限流的完整邏輯
Http2Session ISession的實現類 主要屬性:
1. EndPoint endPoint, 表征了此Session的網絡端點,對於網絡的操作通過調用endPoint的方法實現
2. Generator generator,用於按需生成各種格式的Frame,Frame被最終寫入endPoint中 
3. Listener listener,Session中被動接口的邏輯實現,面向接口編程,支持多種實現
4. FlowControlStrategy flowControl前面已經講述
5. HTTP2Flusher flusher前面也已講述
主要方法:
1.newStream(),創建新的流對象,以及HeaderFrame,將流寫入Session的流緩存中,流緩存通過ConcurrentHashMap實現;並將流和HeaderFrame追加到Http2Flusher對象的ArrayQueue中;
2. push(), settings(), ping(), reset()的實現雷同,最終都是將對應格式的Frame放入Http2Flusher的ArrayQueue中。Http2Flusher是真正輸出Frame的控制類。
3. onData(),接收DataFrame時的處理方法,首先更新當前FlowControl對象中的WindowSize,並執行Window限流邏輯,若未超出限流控制,則調用Stream的處理方法處理接收到的數據,否則直接丟棄當前Frame,最后將WindowSize恢復之前值
4. onHeaders()接收HeaderFrame時的處理方法,抽象方法,交由子類實現
5. onPriority(),Jetty默認未支持客戶端發起的對優先級的支持
6. onReset(), onSettings(),onPing(),onGoAway(),onWindowUpdate(),onConnectionFailure()執行對應邏輯,通過Listener接口,支持對於這些請求數據的自定義實現
HTTP2Stream IStream的實現類 重點說明: 
實現了IStream的主動接口及其被動接口Stream.Listener。其主動接口一般是通過調用對應的ISession接口實現
HTTP2ServerSession 繼承HTTP2Session,實現Server端Session特有的邏輯 重點說明:
特有邏輯包括ServerSession在接收onPreface時,需回復一個Settings Frame;在接收Headers請求時需創建RemoteStream對象;當接收ServerPush時,報出異常,HTTP2中Client不能向Server發送Server Push。
DataFrame HTTP2協議的各種數據格式的封閉 重點說明: 
針對不同的數據格式,如ServerPush,Preface等,有對應的子類實現
DataGenerator 構建如上的DataFrame 重點說明:
對於不同的數據格式有不同的子類實現
parser包 對接收的數據格式進行解析 重點說明:
對接收的數據格式進行解析

 

四、如何實現HTTP2

 

HTTP2還未被所有瀏覽器所支持,因此在實施時要支持多種協議並存.

需要Http Server端支持HTTP2協議,據我所知Tengine尚未支持,已支持的Server列表https://github.com/http2/http2-spec/wiki/Implementations

若要充分利用HTTP2的所有優點,需要在應用程序端(甚至是JAVA)的輸出行為作智能處理,如通過大數據來分析哪些資源適合用Server Push並行輸出,哪些資源優先級可以隱藏低,如何在性能與復雜度及維護成本之間做出平衡,需要業內更多的人努力和嘗試,


免責聲明!

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



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