SPDY、HTTP/2、QUIC協議
1 SPDY協議
1.1 概述
SPDY為speedy(單詞原意:快速的)的縮寫,讀音也就是speedy。
SPDY協議已釋出過4個草案,分別為版本1、2、3、3.1。目前版本4已在試驗階段,但未釋出,Chromium裡已有一些針對版本4的程式碼。
- 複用連線,可在一個TCP連線上傳送多個資源。應對了TCP慢啟動的特性。
- 請求分優先順序,重要的資源優先傳送。
- HTTP頭部資料也被壓縮,省流量。
- 伺服器端可主動連線客戶端來推送資源(Server Push)。
缺點:
- 單連線會因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),但有以下區別:
- SPDY的頭部都是8個位元組,根據其中一些位的數值不同來表示不同的資訊,並把HTTP的頭部放到SPDY的載荷裡。
- 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_STREAM、SYN_REPLY、RST_STREAM、HEADERS)的payload裡。
控制幀的8種類型及作用:
- SYN_STREAM:建立流,在payload裡攜帶請求(Request)。
- SYN_REPLY:回覆建立流,在payload裡攜帶HTTP頭部。注意:SPDY把HTTP response拆開,response header放在控制幀SYN_REPLY的payload裡並經過壓縮,response entity放在資料幀裡。
- RST_STREAM:報告流錯誤,payload裡攜帶錯誤型別。
- SETTINGS:查詢或設定控制資訊。可處理的資訊有8種:上傳頻寬、下載頻寬、Round Trip時間、最大並行流數量、TCP的CWND值、下載重傳率、初始視窗(Window)值、證書數量。
- PING:一種機制來測量Round Trip時間。
- GOAWAY:通知即將斷開TCP連線。
- HEADERS:可做補充SVN_REPLY中的response header,或傳遞私有資訊,特定的應用可用做自定義的擴充套件。
- 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的,差別是:
- 增加了HTTP/1.1 Upgrade的機制,可在TCP上直接使用HTTP/2,不像SPDY那樣必須在TLS上。
- HTTPS連線時使用NPN的規範版ALPN(Applcation Layer Protocol Negociation)。
- 更完善的協議商討和確認流程。
- 更完善的Server Push流程。
- 增加控制幀的種類,並對幀格式考慮得更細緻。
- 有新演算法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個缺點:
- 單個包(packet)丟失會阻塞整個流(stream)。
- TCP避免擁堵的機制做的不好,導致頻寬降低和序列化的等待時間開銷。
- TLS會話重連的等待時間開銷。握手機制帶來額外的Round Trip。
- 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.com和www.cloudflare.com。國內還沒有網站支援。(注,此調查結果很粗淺,不可當權威結論)4.4 Browser端應用現狀
4.4.1 測試方法
4.4.2 資料
根據第三方資料,支援SPDY的瀏覽器有:
- Internet Explorer 11 部分支援
- Firefox 13+
- Chrome 4+
- Opera 12.1+
- Android系統瀏覽器3.0+(應該是錯的,測試的結果是4.1+才對)
- Opera Mobile 12.1+
- Chrome for Android 33+
- Firefox for Android 26+
5 瀏覽器實現方案
SPDY對瀏覽器的實現來說,工作在載入框架的網路層。假如已實現SPDY,下圖描述網路層內部再分層細化以及各細化層的職責:
無論是HTTP還是SPDY,在一次載入流程中都需要各細化層承擔所有的職責。在程式碼實現來看,若HTTP和SPDY有不同,則需要對各職責設計基類,HTTP和SPDY各自繼承基類以實現不同的過程。
SPDY特殊實現的職責有:
- Callback回撥機制。SPDY的HTTP header是壓縮的,要與普通HTTP流程對接的話,要麼先行解壓,要麼由callback解壓。
- Protocol Transport協議傳輸過程控制。特別是Server Push特性。
- error錯誤處理
- SPDY全雙工。SPDY的socket是全雙工應用,同時傳送和接收,和一般的HTTP先發送後接收不同。
- Framing裝幀。這層大部分都和HTTP不同。
- SSL/TLS handshake握手過程。因為SPDY有NPN。
- SpdyConnection。Connection一般由URL的scheme、host、port來區分,SPDY和HTTPS的這些區分點全都相同,故connection的複用需增加protocol來區分。
6 網站是否該支援SPDY
暫無必要支援SPDY、HTTP/2和QUIC。
原因:
- SPDY是公司標準,還不是行業標準,存在缺陷,待完善。
- SPDY成熟的時候就會被接納並完善成為行業標準甚至國際標準,那時候再支援也不遲。HTTP/2草案就是基於SPDY的,且HTTP/2優於SPDY,SPDY遲早會退出歷史舞臺,屆時業界會大量支援HTTP/2。
- Server端本身對SPDY的支援不完善,未完全實現所有特性,且存在bug。網站貿然使用的話存在一定風險。Apache2.2 + mod_spdy只支援SPDY3,Nginx1.5.1只支援SPDY3.1,未實現Server Push。等到Server端程式較完善的時候再做也不遲。收費的Server端程式沒有一個開始支援SPDY,等到他們開始支援的時候,可認為是一個標誌,代表業界會開始做很多配套的東西來支援新標準。
- Server端並未普及,已應用的網站寥寥無幾。
- 支援SPDY的瀏覽器在中國的份額低於50%,網站還沒迫切必要支援SPDY。Safari完全不支援,即SPDY還未獲Apple認可。