1. 程式人生 > >SPDY、HTTP/2、QUIC協議

SPDY、HTTP/2、QUIC協議

1 SPDY協議

1.1 概述

SPDY為speedy(單詞原意:快速的)的縮寫,讀音也就是speedy。

SPDY協議已釋出過4個草案,分別為版本1、2、33.1。目前版本4已在試驗階段,但未釋出,Chromium裡已有一些針對版本4的程式碼。

  1. 複用連線,可在一個TCP連線上傳送多個資源。應對了TCP慢啟動的特性。
  2. 請求分優先順序,重要的資源優先傳送。
  3. HTTP頭部資料也被壓縮,省流量。
  4. 伺服器端可主動連線客戶端來推送資源(Server Push)。

缺點:

  1. 單連線會因TCP線頭阻塞(head-of-line blocking)的特性而傳輸速度受限。加上存在可能丟包的情況,其負面影響已超過壓縮頭部和優先順序控制帶來的好處。

由於這些缺點,SPDY在小網站(資原始檔數量較少)的效果不明顯,有可能比多併發連線更慢。(由此催生了QUIC)

1.2 協議層次

基於安全的考慮,SPDY規定建立在TLS之上,即URL scheme為https。發明者表示TLS的握手是在一定程度上佔用了時間和流量,但網路安全是必然的趨勢,所以不計較這一成本。協議層次如下:

   SPDY  ←  HTTP  
    ↓
   TLS   ←  NPN  
    ↓
   TCP

對比普通的HTTPS協議層次:

    HTTP  
     ↓
  SSL/TLS   
     ↓
    TCP

SPDY協議雖然在TLS基礎上代替了HTTP協議,但SPDY的內容又包含了HTTP協議的內容,用設計模式來理解就是應用裝飾者模式擴充套件了HTTP。

1.3 NPN

NPN簡單來說就是在TLS的握手階段增加一些欄位來表明伺服器端和客戶端希望在TLS基礎上使用HTTP之外的(SPDY)協議。NPN同樣是Google提出的,為SPDY鋪路。

Client端程式的實現是:握手前對OpenSSL(或封裝它的庫)設定可接受哪些協議,握手後獲取伺服器選擇了哪個協議,然後按選擇的協議進行通訊。

1.4 資料格式

本節不會完整介紹SPDY,只講重點,並假定讀者熟悉HTTP協議而不解釋SPDY中類似HTTP的概念。

SPDY把一次單向傳輸(伺服器到客戶端或客戶端到伺服器)的內容稱作幀(frame),按協議組裝幀內容稱為裝幀(framing)。幀內容分為頭部(header)和載荷(payload),類似於HTTP的頭部(header)和實體(entity),但有以下區別:

  1. SPDY的頭部都是8個位元組,根據其中一些位的數值不同來表示不同的資訊,並把HTTP的頭部放到SPDY的載荷裡。
  2. HTTP的實體(除POST資訊外)是檔案資料(data),SPDY的載荷除了可以是檔案資料還可以是其它資訊。

根據載荷的內容,幀分為控制幀和資料幀。

控制幀的資料格式:

+----------------------------------+
|C| Version(15bits) | Type(16bits) |
+----------------------------------+
| Flags (8)  |  Length (24 bits)   |
+----------------------------------+
|               Data               |
+----------------------------------+

資料幀的資料格式:

+----------------------------------+
|C|       Stream-ID (31bits)       |
+----------------------------------+
| Flags (8)  |  Length (24 bits)   |
+----------------------------------+
|               Data               |
+----------------------------------+

各資料位的意義:

  • C是第一個bit,值為0或1分別表示資料幀和控制幀。
  • Version為SPDY協議版本號,目前為3。
  • Type用作區分控制幀的型別
  • Flags標記一些操作指示,不同的Type有不同的Flag。常見的是FLAG_FIN表示一個Stream結束。
  • Length表示Data的資料長度。
  • Data也就是payload。資料幀的Data就是一個檔案(HTML文件、圖片、指令碼等),控制幀的Data根據Type不同而有不同。
  • Stream-ID記錄流水號。

SPDY把一次HTTP Request/Response來回稱作流(Stream),因為複用TCP連線,所以一個SPDY連線裡會有多個流。為了區分不同的流,用Stream-ID來標記流水號(注:因為可以reload,所以不能以URL來確定一個流)。Stream-ID還存在於4種控制幀(SYN_STREAMSYN_REPLYRST_STREAMHEADERS)的payload裡。

控制幀的8種類型及作用:

  1. SYN_STREAM:建立,在payload裡攜帶請求(Request)。
  2. SYN_REPLY:回覆建立流,在payload裡攜帶HTTP頭部。注意:SPDY把HTTP response拆開,response header放在控制幀SYN_REPLY的payload裡並經過壓縮,response entity放在資料幀裡。
  3. RST_STREAM:報告流錯誤,payload裡攜帶錯誤型別。
  4. SETTINGS:查詢或設定控制資訊。可處理的資訊有8種:上傳頻寬、下載頻寬、Round Trip時間、最大並行流數量、TCP的CWND值、下載重傳率、初始視窗(Window)值、證書數量。
  5. PING:一種機制來測量Round Trip時間。
  6. GOAWAY:通知即將斷開TCP連線。
  7. HEADERS:可做補充SVN_REPLY中的response header,或傳遞私有資訊,特定的應用可用做自定義的擴充套件。
  8. WINDOW_UPDATE:設定視窗大小。

下圖為幀格式的整理參考(需對照協議文件來理解具體意義,可跳過,點選檢視大圖):


1.5 流程

普通流程如下圖:


Server Push的server端流程:回覆client端的SYN_STREAM之後,再在server端發起SYN_STREAM,並在payload中用欄位Associated_To_Stream_ID表示這個推送與哪個stream關聯。

2 HTTP/2

2.1 概述

HTTP/2由標準化組織來制定,是基於SPDY的,差別是:

  1. 增加了HTTP/1.1 Upgrade的機制,可在TCP上直接使用HTTP/2,不像SPDY那樣必須在TLS上。
  2. HTTPS連線時使用NPN的規範版ALPN(Applcation Layer Protocol Negociation)。
  3. 更完善的協議商討和確認流程。
  4. 更完善的Server Push流程。
  5. 增加控制幀的種類,並對幀格式考慮得更細緻。
  6. 有新演算法HPACK專門壓縮SPDY header block。

HTTP/2文件帶有一些示例和詳細說明,這是SPDY沒有的。

Chromium最新程式碼和Google網站已支援HTTP2-10(HTTP/2第10版草案)。

2.2 ALPN

   Client                                              Server

   ClientHello                     -------->       ServerHello
     (ALPN extension &                               (ALPN extension &
      list of protocols)                              selected protocol)
                                                   Certificate*
                                                   ServerKeyExchange*
                                                   CertificateRequest*
                                   <--------       serverhellodone 
certificate* 
clientkeyexchange* 
certificateverify* 
[changecipherspec] 
finished                           -------->
                                                   [ChangeCipherSpec]
                                   <--------       Finished
   Application Data                <------->       Application Data

目前Chromium的PC釋出版已經在使用ALPN,不用NPN了。

2.3 TCP上的應用

HTTP/2可使用http或https scheme作為URL。

當使用http scheme時,client先用HTTP/1.1的request發給server,但要加入header Upgrade和HTTP2-Settings。格式為:

GET /default.htm HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

如果server支援HTTP/2,則以狀態碼101回覆,形式如下:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2

[ HTTP/2 connection ...

然後雙方開始以HTTP/2作為傳輸協議。否則以HTTP/1.1回覆response,即HTTP/1.1 200 OK。

3 QUIC

概要設計文件從TCP/UDP特性、網路安全等考慮出發,做了非常多設計思路方面的論述,開頭就闡述了SPDY的4個缺點

  1. 單個包(packet)丟失會阻塞整個流(stream)。
  2. TCP避免擁堵的機制做的不好,導致頻寬降低和序列化的等待時間開銷。
  3. TLS會話重連的等待時間開銷。握手機制帶來額外的Round Trip。
  4. TLS解密的開銷。先到的包必須等後面的包到來才能解密。

可以認為QUIC是為了解決SPDY在TCP遇到的瓶頸而在UDP上做探索所設計的方案。參考SPDY來理解,可認為QUIC的傳輸內容分兩層,高層類似SPDY,低層是在UDP上模仿實現TCP的面向連線特性和可靠性並加入類似TLS的加密過程。

QUIC的文件還算未完成的狀態,且Chromium的實現程式碼也在完善中,這還是個試驗性的半成品,沒有效能比較的資料。只淺淺研究即止,不深入了。

4 研究與調查

4.1 SPDY伺服器搭建

4.1.1 Apache

環境配置為Linux + Apache2.2 + mod_spdy。其中mod_spdy是Chromium為Apache開發的外掛,只支援Apache2.2,直接安裝外掛包即可。SPDY協議支援版本為3。

4.1.2 Nginx

環境配置為Linux + Nginx1.5.11,需要編譯原始碼來啟用SPDY,普通釋出包並不支援。SPDY協議支援版本為3.1,還不支援Server Push。

4.1.3 份額

4.2 Wireshark截包

Chromium為Wireshark1.7.1做了原始碼patch,名為spdyshark,需要下載Wireshark原始碼和spdyshark原始碼共同編譯才能令Wireshark支援SPDY協議。具體的編譯安裝方法請參考《Linux Mint下編譯安裝支援SPDY協議的Wireshark》

4.3 Server端應用現狀

4.3.1 調查方法

調查Web伺服器是否支援SPDY,可使用第三方網站的方法:訪問http://spdycheck.org/,在網頁中輸入網址即可反饋結果。例如:


但是國內網站並非全站都用HTTPS scheme,所以需要人工找到登入賬號的頁面來做測試。

還可使用Wireshark截包,在TLS的Server Hello資訊中找Extension,ALPN會顯示Unknown 16,NPN能識別出是Extension: next_protocol_negotiation。

可知目前Google網站用3.1:


Facebook用2和3:


4.3.2 調查結果

國內外的常見網站看了看,只發現四家:Google、Facebook、wordpress.comwww.cloudflare.com。國內還沒有網站支援。(注,此調查結果很粗淺,不可當權威結論)

4.4 Browser端應用現狀

4.4.1 測試方法

4.4.2 資料

根據第三方資料,支援SPDY的瀏覽器有:

  1. Internet Explorer 11 部分支援
  2. Firefox 13+
  3. Chrome 4+
  4. Opera 12.1+
  5. Android系統瀏覽器3.0+(應該是錯的,測試的結果是4.1+才對)
  6. Opera Mobile 12.1+
  7. Chrome for Android 33+
  8. Firefox for Android 26+

5 瀏覽器實現方案

SPDY對瀏覽器的實現來說,工作在載入框架的網路層。假如已實現SPDY,下圖描述網路層內部再分層細化以及各細化層的職責:


無論是HTTP還是SPDY,在一次載入流程中都需要各細化層承擔所有的職責。在程式碼實現來看,若HTTP和SPDY有不同,則需要對各職責設計基類,HTTP和SPDY各自繼承基類以實現不同的過程。

SPDY特殊實現的職責有:

  1. Callback回撥機制。SPDY的HTTP header是壓縮的,要與普通HTTP流程對接的話,要麼先行解壓,要麼由callback解壓。
  2. Protocol Transport協議傳輸過程控制。特別是Server Push特性。
  3. error錯誤處理
  4. SPDY全雙工。SPDY的socket是全雙工應用,同時傳送和接收,和一般的HTTP先發送後接收不同。
  5. Framing裝幀。這層大部分都和HTTP不同。
  6. SSL/TLS handshake握手過程。因為SPDY有NPN。
  7. SpdyConnection。Connection一般由URL的scheme、host、port來區分,SPDY和HTTPS的這些區分點全都相同,故connection的複用需增加protocol來區分。
除了Chromium自己外,其SPDY文件還列出了幾種實現。C/C++的其它實現,都有個共同點:因為工作在底層,依賴比較多的外部庫程式碼。而且他們最近三個月都還有更新,多數並未支援所有的SPDY特性,並且在修復bug。所以程式碼的完善程度還不能達到瀏覽器級別的標準。

6 網站是否該支援SPDY

暫無必要支援SPDY、HTTP/2和QUIC

原因:

  1. SPDY是公司標準,還不是行業標準,存在缺陷,待完善。
  2. SPDY成熟的時候就會被接納並完善成為行業標準甚至國際標準,那時候再支援也不遲。HTTP/2草案就是基於SPDY的,且HTTP/2優於SPDY,SPDY遲早會退出歷史舞臺,屆時業界會大量支援HTTP/2。
  3. Server端本身對SPDY的支援不完善,未完全實現所有特性,且存在bug。網站貿然使用的話存在一定風險。Apache2.2 + mod_spdy只支援SPDY3,Nginx1.5.1只支援SPDY3.1,未實現Server Push。等到Server端程式較完善的時候再做也不遲。收費的Server端程式沒有一個開始支援SPDY,等到他們開始支援的時候,可認為是一個標誌,代表業界會開始做很多配套的東西來支援新標準。
  4. Server端並未普及,已應用的網站寥寥無幾。
  5. 支援SPDY的瀏覽器在中國的份額低於50%,網站還沒迫切必要支援SPDY。Safari完全不支援,即SPDY還未獲Apple認可。