轉載自 | 小米運維(公衆號 ID:MI-SRE)html
HTTP/2 是現行 HTTP 協議(HTTP/1.x)的替代,但它不是重寫,HTTP 方法 / 狀態碼 / 語義都與 HTTP/1.x 同樣。不過,HTTP/2 修改了數據格式化(分幀)以及在客戶端與服務器間傳輸的方式。HTTP/2 基於 SPDY3,專一於性能,最大的一個目標是在用戶和網站間只用一個鏈接。前端
HTTP/2 經過支持完整的請求與響應複用來減小延遲,經過有效壓縮 HTTP 報頭字段將協議開銷降至最低,同時增長對請求優先級和服務器推送的支持。java
HTTP/2 協議由如下兩個 RFC 組成:nginx
影響一個 HTTP 網絡請求的因素主要有兩個:帶寬和延遲。在當今的網絡狀況下,帶寬通常再也不是瓶頸,因此咱們主要討論下延遲。延遲通常由下面幾個因素所形成:git
鏈接沒法複用:
鏈接沒法複用會致使每次請求都經歷三次握手和慢啓動。三次握手在高延遲的場景下影響較明顯,慢啓動則對文件類大請求影響較大。github
線頭阻塞(Head-Of-Line Blocking):
致使帶寬沒法被充分利用,以及後續健康請求被阻塞。HOLB 是指在 HTTP/1.x 中,因爲服務器必須按接受請求的順序發送響應的規則限制,那麼假設瀏覽器在一個(tcp)鏈接上發送了兩個請求,那麼服務器必須等第一個請求響應完畢才能發送第二個響應——HOLB。雖然如今瀏覽器容許每一個 origin 創建 6 個 connection,但大量網頁動輒幾十個或上百個資源,HOLB 依然是主要問題。
協議開銷大:
HTTP/1.x 中 header 內容過大(每次請求 header 基本不怎麼變化),增長了傳輸的成本。
安全因素:
在 HTTP 中傳輸的內容都是明文,客戶端和服務端雙方沒法驗證身份。web
鏈接複用:
在用戶和網站之間只用一個鏈接,避免後續創建鏈接過程當中的幾個往返和慢啓動,同時減小了服務器的資源消耗。算法
沒有線頭阻塞:
採用新的二進制分幀層的機制,組成消息的幀能夠亂序發送,幀到達對端從新組裝,不須要等待前面的幀到達後再發送。chrome
報頭壓縮:
HTTP/2 協議中採用 HPACK 來壓縮請求頭和響應頭,下降協議開銷。數據庫
更加安全:
當前主流瀏覽器,都只支持基於 HTTPS 部署的 HTTP/2。
HTTP 2.0 性能加強的核心,全在於新增的二進制分幀層,它定義瞭如何封裝 HTTP 消息並在客戶端和服務器之間傳輸,和 HTTP/1.x 對好比下圖:
這裏所謂的 「層」,指的是位於套接字接口與應用可見的高級 HTTP API 之間一個通過優化的新編碼機制:HTTP 的語義(包括各類動詞、方法、標頭)都不受影響,不一樣的是傳輸期間對它們的編碼方式變了。HTTP/1.x 協議以換行符做爲純文本的分隔符,而 HTTP/2 將全部傳輸的信息分割爲更小的消息和幀,並採用二進制格式對它們編碼。
這樣一來,客戶端和服務器爲了相互理解,都必須使用新的二進制編碼機制:HTTP/1.x 客戶端沒法理解只支持 HTTP/2 的服務器,反之亦然。不過沒關係,現有的應用沒必要擔憂這些變化,由於客戶端和服務器會替咱們完成必要的分幀工做。
新的二進制分幀機制改變了客戶端與服務器之間交換數據的方式。 爲了說明這個過程,咱們須要瞭解 HTTP/2 的三個概念:
這些概念的關係總結以下:
幀是最小的通訊單位,承載着特定類型的數據,例如 HTTP 標頭、消息負載等等。 來自不一樣 數據流的幀能夠交錯發送,而後再根據每一個幀頭的數據流標識符從新組裝,以下圖:
簡言之,HTTP/2 將 HTTP 協議通訊分解爲二進制編碼幀的交換,這些幀對應着特定數據流中的消息。全部這些都在一個 TCP 鏈接內複用。這是 HTTP/2 協議全部其餘功能和性能優化的基礎。
在 HTTP/1.x 中,若是客戶端要想發起多個並行請求以提高性能,則必須使用多個 TCP 鏈接。這是 HTTP/1.x 交付模型的直接結果,該模型能夠保證每一個鏈接每次只交付一個響應(響應排隊)。更糟糕的是,這種模型也會致使隊首阻塞,從而形成底層 TCP 鏈接的效率低下。
HTTP/2 中新的二進制分幀層突破了這些限制,實現了完整的請求和響應複用:客戶端和服務器能夠將 HTTP 消息分解爲互不依賴的幀,而後交錯發送,最後再在另外一端把它們從新組裝起來。
上圖捕捉了同一個鏈接內並行的多個數據流。客戶端正在向服務器傳輸一個 DATA 幀(數據流 5),與此同時,服務器正向客戶端交錯發送數據流 1 和數據流 3 的一系列幀。所以,一個鏈接上同時有三個並行數據流。
將 HTTP 消息分解爲獨立的幀,交錯發送,而後在另外一端從新組裝是 HTTP 2 最重要的一項加強。事實上,這個機制會在整個網絡技術棧中引起一系列連鎖反應,從而帶來巨大的性能提高,讓咱們能夠:
HTTP/2 中的新二進制分幀層解決了 HTTP/1.x 中存在的隊首阻塞問題,也消除了並行處理和發送請求及響應時對多個鏈接的依賴。結果,應用速度更快、開發更簡單、部署成本更低。
HTTP 1.1 的有一個缺點是:當一個含有確切值的 Content-Length 的 HTTP 消息被送出以後,你就很難中斷它了。固然,一般你能夠斷開整個 TCP 鏈接(但也不老是能夠這樣),但這樣致使的代價就是須要經過三次握手來從新創建一個新的 TCP 鏈接。
一個更好的方案是隻終止當前傳輸的消息並從新發送一個新的。在 HTTP/2 裏面,咱們能夠經過發送 RST_STREAM 幀來實現這種需求,從而避免浪費帶寬和中斷已有的鏈接。
將 HTTP 消息分解爲不少獨立的幀以後,咱們就能夠複用多個數據流中的幀,客戶端和服務器交錯發送和傳輸這些幀的順序就成爲關鍵的性能決定因素。爲了作到這一點,HTTP/2 標準容許每一個數據流都有一個關聯的權重和依賴關係:
數據流依賴關係和權重的組合讓客戶端能夠構建和傳遞 「優先級樹」,代表它傾向於如何接收響應。反過來,服務器可使用此信息經過控制 CPU、內存和其餘資源的分配設定數據流處理的優先級,在資源數據可用以後,帶寬分配能夠確保將高優先級響應以最優方式傳輸至客戶端。
如上圖,HTTP/2 內的數據流依賴關係經過將另外一個數據流的惟一標識符做爲父項引用進行聲明;若是忽略標識符,相應數據流將依賴於 「根數據流」。聲明數據流依賴關係指出,應儘量先向父數據流分配資源,而後再向其依賴項分配資源。換句話說,「請先處理和傳輸響應 D,而後再處理和傳輸響應 C」。
共享相同父項的數據流(即,同級數據流)應按其權重比例分配資源。 例如,若是數據流 A 的權重爲 12,其同級數據流 B 的權重爲 4,那麼要肯定每一個數據流應接收的資源比例,請執行如下操做:
將全部權重求和:4 + 12 = 16
將每一個數據流權重除以總權重:A = 12/16, B = 4/16 所以,數據流 A 應得到四分之三的可用資源,數據流 B 應得到四分之一的可用資源;數據流 B 得到的資源是數據流 A 所獲資源的三分之一。 咱們來看一下上圖中的其餘幾個動手示例:順序爲從左到右:
數據流 A 和數據流 B 都沒有指定父依賴項,依賴於顯式 「根數據流」;A 的權重爲 12,B 的權重爲 4。所以,根據比例權重:數據流 B 得到的資源是 A 所獲資源的三分之一。 數據流 D 依賴於根數據流;C 依賴於 D。所以,D 應先於 C 得到完整資源分配。權重不重要,由於 C 的依賴關係擁有更高的優先級。 數據流 D 應先於 C 得到完整資源分配;C 應先於 A 和 B 得到完整資源分配;數據流 B 得到的資源是 A 所獲資源的三分之一。 數據流 D 應先於 E 和 C 得到完整資源分配;E 和 C 應先於 A 和 B 得到相同的資源分配;A 和 B 應基於其權重得到比例分配。
如上面的示例所示,數據流依賴關係和權重的組合明確表達了資源優先級,這是一種用於提高瀏覽性能的關鍵功能,網絡中擁有多種資源類型,它們的依賴關係和權重各不相同。不只如此,HTTP/2 協議還容許客戶端隨時更新這些優先級,進一步優化了瀏覽器性能。換句話說,咱們能夠根據用戶互動和其餘信號更改依賴關係和從新分配權重。
注:數據流依賴關係和權重表示傳輸優先級,而不是要求,所以不能保證特定的處理或傳輸順序。即,客戶端沒法強制服務器經過數據流優先級以特定順序處理數據流。 儘管這看起來違反直覺,但倒是一種必要行爲。 咱們不但願在優先級較高的資源受到阻止時,還阻止服務器處理優先級較低的資源。
有了新的分幀機制後,HTTP/2 再也不依賴多個 TCP 鏈接去並行複用數據流;每一個數據流都拆分紅不少幀,而這些幀能夠交錯,還能夠分別設定優先級。所以,全部 HTTP/2 鏈接都是永久的,並且僅須要每一個來源一個鏈接,隨之帶來諸多性能優點。
大多數 HTTP 傳輸都是短暫且急促的,而 TCP 則針對長時間的批量數據傳輸進行了優化。 經過重用相同的鏈接,HTTP/2 既能夠更有效地利用每一個 TCP 鏈接,也能夠顯著下降總體協議開銷。不只如此,使用更少的鏈接還能夠減小佔用的內存和處理空間,也能夠縮短完整鏈接路徑(即,客戶端、可信中介和源服務器之間的路徑)這下降了總體運行成本並提升了網絡利用率和容量。 所以,遷移到 HTTP/2 不只能夠減小網絡延遲,還有助於提升通量和下降運行成本。
在 HTTP/2 RFC 文檔中建議實現時客戶端不該該在給定的目的地上打開多個 HTTP/2 鏈接,目的地是由給定的 URI 肯定的 IP 地址及 TCP 端口,或者配置的代理 IP 和端口。固然客戶端可使用不相同的服務端名稱標識值或者提供不同的 ssl 證書對相同的 IP 地址及 TCP 端口打開多個鏈接,但應該避免對相同的配置上建立多個鏈接。
注:鏈接數量減小對提高 HTTPS 部署的性能來講是一項特別重要的功能:能夠減小開銷較大的 TLS 鏈接數、提高會話重用率,以及從總體上減小所需的客戶端和服務器資源。
流量控制是一種阻止發送方向接收方發送大量數據的機制,以避免超出後者的需求或處理能力:發送方可能很是繁忙、處於較高的負載之下,也可能僅僅但願爲特定數據流分配固定量的資源。例如,客戶端可能請求了一個具備較高優先級的大型視頻流,可是用戶已經暫停視頻,客戶端如今但願暫停或限制從服務器的傳輸,以避免提取和緩衝沒必要要的數據。再好比,一個代理服務器可能具備較快的下游鏈接和較慢的上游鏈接,而且也但願調節下游鏈接傳輸數據的速度以匹配上游鏈接的速度來控制其資源利用率;等等。
不過,因爲 HTTP/2 數據流在一個 TCP 鏈接內複用,TCP 流控制既不夠精細,也沒法提供必要的應用級 API 來調節各個數據流的傳輸。爲了解決這一問題,HTTP/2 提供了一組簡單的構建塊,這些構建塊容許客戶端和服務器實現其本身的數據流和鏈接級流量控制:
HTTP/2 未指定任何特定算法來實現流量控制。不過,它提供了簡單的構建塊並推遲了客戶端和服務器實現,能夠實現自定義策略來調節資源使用和分配,以及實現新傳輸能力,同時提高網絡應用的實際性能和感知性能。
例如,應用層流量控制容許瀏覽器僅提取一部分特定資源,經過將數據流流控制窗口減少爲零來暫停提取,稍後再行恢復。換句話說,它容許瀏覽器提取圖像預覽或首次掃描結果,進行顯示並容許其餘高優先級提取繼續,而後在更關鍵的資源完成加載後恢復提取。
HTTP/2 新增的另外一個強大的新功能是,服務器能夠對一個客戶端請求發送多個響應。 換句話說,除了對最初請求的響應外,服務器還能夠向客戶端推送額外資源(以下圖),而無需客戶端明確地請求。
注:HTTP/2 打破了嚴格的請求 - 響應語義,支持一對多和服務器發起的推送工做流,在瀏覽器內外開啓了全新的互動可能性。這是一項使能功能,對咱們思考協議、協議用途和使用方式具備重要的長期影響。
爲何在瀏覽器中須要一種此類機制呢?一個典型的網絡應用包含多種資源,客戶端須要檢查服務器提供的文檔才能逐個找到它們。那爲何不讓服務器提早推送這些資源,從而減小額外的延遲時間呢?服務器已經知道客戶端下一步要請求什麼資源,這時候服務器推送便可派上用場。
事實上,若是在網頁中內聯過 CSS、JavaScript,或者經過數據 URI 內聯過其餘資產,那麼就已經親身體驗過服務器推送了。對於將資源手動內聯到文檔中的過程,咱們其實是在將資源推送給客戶端,而不是等待客戶端請求。使用 HTTP/2,咱們不只能夠實現相同結果,還會得到其餘性能優點。 推送資源能夠進行如下處理:
全部服務器推送數據流都由 PUSH_PROMISE 幀發起,代表了服務器向客戶端推送所述資源的意圖,而且須要先於請求推送資源的響應數據傳輸。這種傳輸順序很是重要:客戶端須要瞭解服務器打算推送哪些資源,以避免爲這些資源建立重複請求。知足此要求的最簡單策略是先於父響應(即,DATA 幀)發送全部 PUSH_PROMISE 幀,其中包含所承諾資源的 HTTP 標頭。
在客戶端接收到 PUSH_PROMISE 幀後,它能夠根據自身狀況選擇拒絕數據流(經過 RST_STREAM 幀)。 (若是資源已經位於緩存中,可能會發生這種狀況。) 這是一個相對於 HTTP/1.x 的重要提高。 相比之下,使用資源內聯(一種受歡迎的 HTTP/1.x「優化」)等同於 「強制推送」:客戶端沒法選擇拒絕、取消或單獨處理內聯的資源。
使用 HTTP/2,客戶端仍然徹底掌控服務器推送的使用方式。客戶端能夠限制並行推送的數據流數量;調整初始的流控制窗口以控制在數據流首次打開時推送的數據量;或徹底停用服務器推送。這些優先級在 HTTP/2 鏈接開始時經過 SETTINGS 幀傳輸,可能隨時更新。
推送的每一個資源都是一個數據流,與內嵌資源不一樣,客戶端能夠對推送的資源逐一複用、設定優先級和處理。 瀏覽器強制執行的惟一安全限制是,推送的資源必須符合原點相同這一政策:服務器對所提供內容必須具備權威性。
每一個 HTTP 傳輸都承載一組報頭,這些報頭說明了傳輸的資源及其屬性。 在 HTTP/1.x 中,此元數據始終以純文本形式,一般會給每一個傳輸增長 500–800 字節的開銷。若是使用 HTTP Cookie,增長的開銷有時會達到上千字節。爲了減小此開銷和提高性能, HTTP/2 使用 HPACK 壓縮格式壓縮請求和響應標頭元數據,這種格式採用兩種簡單可是強大的技術:
利用 Huffman 編碼,能夠在傳輸時對各個值進行壓縮,而利用以前傳輸值的索引列表,咱們能夠經過傳輸索引值的方式對重複值進行編碼,索引值可用於有效查詢和重構完整的標頭鍵值對。
做爲一種進一步優化方式,HPACK 壓縮上下文包含一個靜態表和一個動態表:靜態表在規範中定義,並提供了一個包含全部鏈接均可能使用的經常使用 HTTP 標頭字段(例如,有效標頭名稱)的列表;動態表最初爲空,將根據在特定鏈接內交換的值進行更新。所以,爲以前未見過的值採用靜態 Huffman 編碼,並替換每一側靜態表或動態表中已存在值的索引,能夠減少每一個請求的大小。
注:在 HTTP/2 中,請求和響應標頭字段的定義保持不變,僅有一些微小的差別:全部標頭字段名稱均爲小寫,請求行如今拆分紅各個 :method、:scheme、:authority 和 :path 僞標頭字段。
至於 HPACK 壓縮的詳細介紹,請點擊這裏:HTTP/2 頭部壓縮技術介紹或者官方 RFC。
爲了測試 HTTP/2 對 web 訪問的性能提高,本人藉助 bbs 產品線的 miui 官方網站,開啓了 tengine 的 HTTP/2 的支持,取一週的訪問數據與 HTTPS、HTTP 訪問數據進行對比分析,詳細結果以下:
響應類型分佈
請求類別 | http | https | http2 |
---|---|---|---|
2xx | 945144 | 927482 | 505702 |
3xx | 243075 | 258331 | 681997 |
4xx | 2372 | 4750 | 2813 |
5xx | 9 | 37 | 88 |
sum | 1190600 | 1190600 | 1190600 |
2xx 請求各個響應時間段佔比(基於 nginx log 的 request_time 數據)
時間 | http | https | http2 |
---|---|---|---|
<50ms | 79.75% | 78.89% | 82.60% |
<100ms | 87.24% | 87.47% | 89.86% |
<150ms | 91.12% | 91.90% | 93.19% |
<200ms | 92.72% | 93.82% | 94.54% |
<2s | 98.99% | 99.71% | 99.48% |
2xx 請求響應時間大於 7 秒的數量 (基於 nginx log 的 request_time 數據)
時間 | http | https | http2 |
---|---|---|---|
>7s | 1960(0.207%) | 603(0.065%) | 950(0.187%) |
>10s | 1519(0.160%) | 420(0.045%) | 638(0.126%) |
>30s | 594(0.062%) | 165(0.017%) | 190(0.037%) |
>60s | 259(0.027%) | 104(0.011%) | 97(0.019%) |
2xx 請求後端響應時間超過 7 秒的數量(基於 nginx log 的 upstream_response_time)
時間 | http | https | http2 |
---|---|---|---|
>7s | 68(0.007%) | 88(0.017%) | 58(0.006%) |
301 請求響應大小(基於 nginx 的 request_length 和 bytes_sent 數據)
/static/image/common/miui9.jpg | 請求數 | 總大小(byte) | avg(byte) | 請求總大小(byte) | 請求avg(byte) |
---|---|---|---|---|---|
http | 2722 | 1460146 | 536 | 3194589 | 1173 |
https | 4695 | 2618278 | 415 | 8019924 | 1708 |
http2 | 16239 | 6751609 | 557 | 1209570 | 74 |
200 請求響應大小(基於 nginx log 的 request_length 和 bytes_sent 數據)
/favicon.ico | 請求數 | 響應總大小(byte) | 響應avg(byte) | 請求總大小(byte) | 請求avg(byte) |
---|---|---|---|---|---|
http | 17658 | 23552229 | 1413 | 15300656 | 866 |
https | 117178 | 165623779 | 1413 | 122356406 | 1044 |
http2 | 80856 | 105496656 | 1304 | 10015908 | 123 |
客戶端分析(基於 nginx log 的 user_agent 數據)
協議 | chrome | MSIE | safari | FireFox | Crawlers | others | unknown | |
---|---|---|---|---|---|---|---|---|
http | 23.53% | 4.26% | 3.56% | 0.67% | 4.01% | 15.07% | 48.22% | |
https | 79.24% | 5.93% | 3.67% | 1.54% | 7.87% | 1.42% | 0.1% | |
http2 | 88.57% | 4.93% | 1.91% | 1.57% | 0% | 2.9% | 0.03% |
平臺分析(基於 nginx log 的 user_agent 數據)
協議 | Android | Windows | Linux | IOS | Darwin | unknown | |
---|---|---|---|---|---|---|---|
http | 28.4% | 16.07% | 0.29% | 2.46% | 0.12% | 51.86% | |
https | 64.85% | 24.65% | 0.62% | 0.54% | 0.29% | 9.05% | |
http2 | 40.06% | 57.62% | 1.49% | 0.44% | 0% | 0.02% |
實現 HTTP/2 很簡單,不過,HTTP/2 並非萬能的銀彈,它只對某些 Web 應用有用,對另一些則沒那麼有用。
若是你使用 SSL/TLS(之後簡稱 TLS),那麼 HTTP/2 能夠提高網站性能。若是你沒有,那在使用 HTTP/2 以前要先支持 TLS。這時候,使用 TLS 的性能損耗大體能夠被使用 HTTP/2 的性能提高抵銷。不過仍是建議你在實際應用以前先測試一下。
HTTP/2 有五大優點:
相應地,HTTP/2 也有五個不足之處。
總之,一切要看性能。這方面,有好消息也有壞消息。
好消息是 nginx 官方團隊在內部對 NGINX 作過測試,結果從理論上可以獲得印證:對於要經過典型網絡延遲請求的混合內容網頁,HTTP/2 的性能好於 HTTP/1.x 和 HTTPS。基於鏈接的 RTT,結果能夠分三種狀況。
這張圖顯示了首次渲染的時間,也就是用戶第一次在本身屏幕上看到網頁內容的時間。這個時間通常認爲關係到用戶對網站響應速度的感知。
然而,每一個網頁都不相同,實際上每一個用戶的會話也不同。若是你託管流媒體或提供大文件下載,那你的決定可能不同,甚至相反。
終止協議意味着客戶端使用指望的協議鏈接代理服務器,好比 TLS 或 HTTP/2,而後代理服務器再去鏈接應用服務器、數據庫服務器等,但不須要使用相同的協議,以下圖所示。
使用獨立的服務器終止協議意味着使用多服務器架構。多服務器多是多個物理服務器、多個虛擬服務器,或者 AWS 這樣的雲環境中的多個虛擬服務器實例。多服務器就比單服務器複雜,或者比應用服務器 / 數據庫服務器的組合複雜。不過,多服務器架構有不少好處,並且不少流量大的網站也必須用這種架構。
配置了服務器或者虛擬服務器以後,不少事情都成爲可能。新服務器能夠分擔其餘服務器的負載,可用於負載平衡、靜態文件緩存和其餘用途。另外,也可讓添加和替換應用服務器或其餘服務器更容易。
NGINX 和 NGINX Plus 常常被用來終止 TLS 和 HTTP/2 協議、負載平衡。已有環境沒必要改動,除非要把 NGINX 服務器挪到前端。
在決定採用 HTTP/2 以前,首先得知道你的代碼有哪些是針對 HTTP/1.x 優化過的。大概有四方面的優化。
後面三種優化都涉及把小文件塞進一個較大的文件裏,目的是減小新建鏈接的初始化和握手,這些操做對 TLS 而言很是費時間。
第一種優化即分域存儲偏偏相反,強制打開多個鏈接,目的是並行地從不一樣的域獲取文件。這兩種看似矛盾的技術對於 HTTP/1.x 下的站點卻十分有效。然而,要用好這兩種技術,必須投入大量時間、精力和資源,用於實現、管理和運維。
在採用 HTTP/2 以前,須要找出應用了這些優化的代碼,分析一下它們會不會影響你的應用設計和工做流程。這樣在遷移到 HTTP/2 以後,就能夠着手改造它們,甚至撤銷某些優化。
事實上,部署 HTTP/2 並不難。若是使用 NGINX,只要在配置文件中啓動相應的協議就能夠了。瀏覽器和服務器會協商採用什麼協議,若是瀏覽器支持 HTTP/2(並且也在使用 TLS),就會使用 HTTP/2。
配置完服務器後,使用支持 HTTP/2 瀏覽器的用戶就會基於 HTTP/2 運行你的應用,而使用舊版本瀏覽器的用戶則會繼續使用 HTTP/1.x 運行你的應用,以下圖所示。若是你的網站流量很是大,那麼應該監測改變先後的性能,對於性能下降的狀況,可能就得撤銷更改。
注意:使用 HTTP/2 及其單鏈接以後,NGINX 某些配置的重要性會很明顯,特別要注意的是 output_buffers、proxy_buffers 和 ssl_buffer_size 等指令,多測試一下。參見 general configuration notes,特定的 SSL 建議,以及 NGINX 關於 SSL 性能的白皮書。
注意:使用 HTTP/2 傳輸密文要格外注意。HTTP/2 的 RFC 中有一個長長的列表,列出了要避免的加密套件。建議你本身也搞一個表格,啓用 ssl_buffer_size,而後在全部經常使用的瀏覽器版本下測試你想用的加密套件。
你說奇怪不,撤銷和修改針對 HTTP/1.x 優化的代碼竟然是實現 HTTP/2 最有創意的部分。這裏面有幾個問題要注意,由於不少事怎麼作都是能夠的。
在開始運做以前,必須考慮舊版本瀏覽器用戶是否好過。以後,能夠採起三個策略撤銷和修改 HTTP/1.x 的優化。
緩存仍是普適的。理論上,緩存操做很是適合小文件特別多的狀況。可是,小文件多也意味着文件 I/O 多。所以一些相近文件的合併仍是必要的,一方面要考慮工做流程,另外一方面要考慮應用性能。建議多關注一下其餘人在過渡到 HTTP/2 過程當中的一些經驗。
分域存儲多是最極端但也最成功的 HTTP/1.x 優化策略。它可以提高 HTTP/1.x 下的應用性能,但在 HTTP/2 之下,其性能提高能夠忽略不講(由於只有一個鏈接。)
對 HTTP/2 友好的分域,要保證如下兩點:
有了這些保障,分域還會繼續對 HTTP/1.x 有效,即域名仍然能夠觸發瀏覽器建立更多鏈接,但對 HTTP/2 則無效,由於這些域名會被當作同一個域,一個鏈接就能夠訪問全部域名了。
若是業務提供的是 web 形式的內容,經過瀏覽器進行訪問,因爲當前大部分的瀏覽器都已經支持 HTTP/2 了,因此基本不需進行任何操做,如下爲支持 HTTP/2 的瀏覽器列表:
瀏覽器 | 支持HTTP/2 | 基於的內核 | 備註 | |
---|---|---|---|---|
Chrome(49) | 支持 | 從49版本開始支持 | ||
IE 11 | 不支持 | win10系統上的IE11支持h2 | ||
Edge(14) | 支持 | 從14版本開始支持 | ||
Safari(10.1) | 支持 | 從10.1版本開始支持,但都須要OSX10.11+以上系統版本 | ||
Firefox(52) | 支持 | 從52版本開始支持 | ||
Opera(47.0.2631.55) | 支持 | 從46版本開始支持 | ||
搜狗瀏覽器(7.1.5.25209) | 支持 | |||
獵豹瀏覽器(6.0.114.15532) | 支持 | |||
2345加速瀏覽器(8.7.0.16013) | 支持 | |||
百度瀏覽器(8.7.5000.4962) | 不支持 | chrome 47 | ||
QQ瀏覽器(9.6.4) | 支持 | chrome 53 | ||
360瀏覽器(9.1.0.346) | 支持 | chrome 55 | ||
360極速瀏覽器(8.7.0.306) | 支持 |
安卓 app 基本採用 JAVA 開發,因爲各個應用採用的與服務端通訊的 http 庫各不相同,有的是採用 jdk 自帶的 httpurlconnection 庫和 httpclient 庫,有的用的是安卓系統自帶的 webview 或者 volley(volley 的 HTTP/2 支持依賴於所使用的 httpstack,默認使用 httpurlconection,但如今也有不少開發者使用第三方的 okhttp 做爲 volley 的 httpstack),而有的開發者直接使用的是第三方庫相似於 okhttp,netty 等,這些 http 庫對 http2.0 的支持狀況各不相同。
基於 java 開發的 http 庫對 HTTP/2 的支持狀況以下:
Golang 的 net/http 庫從 Go1.6 版本開始支持 http2,並默認開啓
名稱 | 支持的版本 | 支持的協商機制 | |
---|---|---|---|
Apache HTTP Server 2.4.17+ | h2,h2c | ALPN,Upgrade,direct | |
Apache Tomcat 8.5+ | h2,h2c | ALPN,Upgrade,direct | |
Nginx | h2,h2c | ALPN,NPN,direct | |
Tengine 2.1.2+ | h2 | ALPN | |
Twisted | h2 | NPN,ALPN | |
Netty | h2,h2c | ALPN,NPN,Upgrade,direct |
在 HTTP/2 的 github 中維護了一份 HTTP/2 協議的實現列表,更加詳細,可供參考。
因爲現有的 URI 結構正在被 HTTP 1.x 使用而不能被更換,因此 HTTP/2 也必須沿用該結構。所以不得不找到一種方式將使用的協議升級至 HTTP/2,好比能夠要求服務器讓它做響應時使用 HTTP/2 來替代舊的協議。
HTTP 1.1 自己就制定過 「升級」 的方案:提供一個首部字段,表示容許服務器在收到舊協議請求的同時,能夠向客戶端發送新協議的響應。但這一方案每每須要花費一次額外的往返通訊來做爲升級的代價。
而這一代價是 SPDY 團隊不想接受的。由於他們只實現了基於 TLS 的 SPDY,因此他們開發了一個 TLS 的擴展去簡化協議的協商。這個擴展被稱做 NPN(Next Protocol Negotiation),藉助於此,服務器會通知客戶端全部它支持的協議,讓客戶端從中選擇一個合適的來進行通信。
IETF 將這個非正式標準 --NPN 進行規範化,從而演變成了 ALPN(Application Layer Protocol Negotiation)。ALPN 會隨着 HTTP/2 的應用被推廣,而 SPDY 的客戶端與服務器則會繼續使用 NPN。
因爲 NPN 先於 ALPN 誕生,而 ALPN 又經歷了一些標準化過程,因此許多早期的 HTTP/2 客戶端和服務器在協商 HTTP/2 時會將這二者同時實現。與此同時,考慮到 SPDY 會使用 NPN,而許多服務器又會同時提供 SPDY 以及 HTTP/2,因此在這些服務器上同時支持 ALPN 以及 NPN 顯然會成爲最理所固然的選擇。
ALPN 和 NPN 的主要區別在於:誰來決定通訊協議。在 ALPN 的描述中,是讓客戶端先發送一個協議優先級列表給服務器,由服務器最終選擇一個合適的。而 NPN 則正好相反,客戶端有着最終的決定權。
ALPN 擴展的具體資料,能夠參考 Jerry Qu 寫的這篇博客:談談 HTTP/2 的協議協商機制
QUIC (Quick UDP Internet Connection,快速 UDP 互聯網鏈接) 是一個新的基於 UDP 的多路複用且安全的傳輸協議,它從頭開始設計,且爲 HTTP/2 語義作了優化。儘管以 HTTP/2 做爲主要的應用協議而構建,然而 QUIC 的構建是基於傳輸和安全領域數十年的經驗的,且實現了使它成爲有吸引力的現代通用傳輸協議的機制。QUIC 提供了等價於
HTTP/2 的多路複用和流控,等價於 TLS 的安全機制,及等價於 TCP 的鏈接語義、可靠性和擁塞控制。
QUIC 徹底運行於用戶空間,它當前做爲 Chromium 瀏覽器的一部分發布給用戶,以便於快速的部署和實驗。做爲基於 UDP 的用戶空間傳輸協議,QUIC 能夠作一些因爲遺留的客戶端和中間設備,或曠日持久的操做系統開發和部署週期的阻礙,而被證實很難在現有的協議中部署的創新。
QUIC 的一個重要目標是經過快速的實驗得到更好的傳輸設計相關的知識。
基於早期的部署的 QUIC 標準化建議爲 [draft-hamilton-quic-transport-protocol],[draft-shade-quic-http2-mapping],[draft-iyengar-quic-loss-recovery],和 [draft-thomson-quic-tls]。
更加詳細的資料請參考這裏:中文文檔; Chromium 的 QUIC 主頁。