1、HTTP1.x存在的問題css
Http1.0時Connection沒法複用,同一時間一個Connection只能處理一個request。Http1.1引入了Request pipelining來解決這一問題,Request pipelining。html
Requestpipeling在FIFO基礎上支持同一Connection併發處理多個Request,這裏的FIFO是指Http Response發送順序必須與Request的發送順序保持一致。
詳情前往https://en.wikipedia.org/wiki/HTTP_pipelining。git
然而它並不完美,仍然有HOL Blocking問題。github
所謂的行首阻塞是因於FIFO的緣由,致使後面的Reponse因爲其以前的Response因爲資源搶佔等緣由沒法輸出而Block。編程
因爲這樣的限制,HTTP/1.0及HTTP/1.1時代須要對Server端建立多個鏈接,經過提升併發度來下降Latency。windows
另外Http2支持Header壓縮,而Header壓縮在此前是不支持的,此前通常是對body進行gzip壓縮。瀏覽器
2、HTTP2的解決方案緩存
HTTP2在協議上真正要求不一樣的Request能夠在同一個Connection上交錯進行,真正作到多路複用。所帶來的好處顯而易見,更少的Connection,更好的併發,更高效的網絡資源利用。服務器
支持流量控制及請求優先級,使得重要的請求優先獲得處理,這一點對於應用來講是個大的優化點,以體驗爲目標,對不一樣的請求劃分優先級以及流量控制,好比異步加載的內容重要性低,能夠設置較低優先級。可是我的以爲這一點要作好很難,要依賴於瀏覽器,應用服務器,應用程序三個地方都有很是好的實現,是不是合理的實現還須要好的度量平臺,視效果而定。網絡
Server Push機制支持Server端應用程序能夠預先輸出內容暫未須要的內容,從而下降潛在的延時。舉例:能夠把css內容與html內容同步輸出,而不須要等待html徹底輸出後,瀏覽器再加載css。
支持對Http Header進行壓縮。
高效的二進制格式(相對文本格式)傳輸。
3、原理分析
將經過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還未被全部瀏覽器所支持,所以在實施時要支持多種協議並存.
須要Http Server端支持HTTP2協議,據我所知Tengine還沒有支持,已支持的Server列表https://github.com/http2/http2-spec/wiki/Implementations。
若要充分利用HTTP2的全部優勢,須要在應用程序端(甚至是JAVA)的輸出行爲做智能處理,如經過大數據來分析哪些資源適合用Server Push並行輸出,哪些資源優先級能夠隱藏低,如何在性能與複雜度及維護成本之間作出平衡,須要業內更多的人努力和嘗試,