全面解析HTTP2:歷史、屬性、偵錯、效能

來源:互聯網
上載者:User

摘要: 相比之前的傳輸協議,HTTP/2在底層方面做了很多優化。有安全、省時、簡化開發、更好的調整複雜網頁、提供快取利用率等優勢,阿裡雲早在去年發佈的CDN6.0服務就已正式支援HTTP/2,存取速度最高可升階68%。今天我們從歷史、屬性、偵錯、效能四個層面來全面解析HTTP/2

寫在前面

超文字傳輸協定(英文:HyperTextTransfer Protocol,縮寫:HTTP)是互連網上套用最為廣泛的一種網路通訊協定。設計HTTP 最初的目的是為了提供一種發佈和接收HTML 網頁的方法。通過HTTP 或者HTTPS 合約要求的資源由統一資源識別項(URI)來標識。

雖然HTTP/1.1穩定執行了十多年了,但HTTP/2來勢洶洶,作為技術工程師有必要學習一下HTTP/2。今天,阿裡雲CDN安防技術專家金九將從歷史、屬性、偵錯、效能四個層面,來全面解析HTTP/2,希望本文可以給你帶來一些啟發。

一、歷史

1 HTTP/0.9
最早的原型,1991年發佈,該組建極其簡單,只支援GET 方法,不支援MIME 類型和各種HTTP 首部等等。

2 HTTP/1.0
1996年發佈。HTTP/1.0在HTTP/0.9的基礎之上新增很多方法,各種HTTP 首部,以及對多媒體物件的處理。

除了GET指令,還引入了POST指令和HEAD指令,豐富了瀏覽器與伺服器的互動手段。

任何格式的內容都可以傳送。這使得互連網不僅可以傳輸文字,還能傳輸影像、視訊、二進位檔案。這為互連網的大發展奠定了基礎。

HTTP要求和回應的格式也變了。除了資料部份,每次通信都必須包括頭資訊(HTTPheader),用來標題一些中繼資料。

可以說,HTTP/1.0是對HTTP/0.9做了革命性的改變,但HTTP/1.0依然有一些缺點,其主要缺點是每個TCP串連只能傳送一個要求,傳送資料完畢後串連就關閉,如果還要要求其他資源,就得再新建一個串連。雖然有些瀏覽器為了解決這個問題,用了一個非標準的Connection頭部,但這個不是標準頭部,各個瀏覽器和伺服器實現有可能不一致,因此不是根本解決辦法。

3HTTP/1.1
1999年正式發佈。HTTP/1.1是本期主流的HTTP 合約。完善了之前HTTP 設計中的結構性缺陷,明確了語義,新增和移除了一些屬性,支援更加複雜的的Web 套用。

經過了十多年將近20年的發展,這個組建的HTTP合約已經很穩定了,跟HTTP/1.0相比,它新增了很多令人信服的新屬性,比如Host合約頭、Range分割要求、預設持久串連、壓縮、分塊傳輸編碼(chunked)、快取處理等等,至今都大量使用,而且很多軟體依賴這些屬性。

雖然HTTP/1.1並不像HTTP/1.0對於HTTP/0.9那樣的革命性,但是也有很多美化,目前主流瀏覽器均預設採用HTTP/1.1。

# 4SPDY
SPDY(發音:speedy)合約由Google開發,主要解決HTTP/1.1 效率不高的問題,於2009年公用,到2016年初結束使命。因為HTTP/2已經被IETF標準化了,以後各種新版瀏覽器都會支援HTTP/2,Google認為SPDY已經沒有存在的必要了,接下來的使命由HTTP/2去完成。

5HTTP/2
HTTP/2是最新的HTTP合約,已於2015年5月份正式發佈,Chrome、IE11、Safari以及Firefox 等主流瀏覽器已經支援HTTP/2合約。

注意是HTTP/2而不是HTTP/2.0,這是因為IETF(InternetEngineering Task Force,互連網工程工作群組)認為HTTP/2已經很成熟了,沒有必要再發佈子組建了,以後要是有重大改動就直接發佈HTTP/3。

其實,HTTP/2的前身是SPDY,甚至它倆的目標、原理和基本實現都差不多。IETF組委會中有很多Google工程師,將SPDY推動成為標準也就不足為奇了。

HTTP/2不僅優化了效能而且相容了HTTP/1.1的語義,其幾大屬性與SPDY差不多,與HTTP/1.1有巨大區別,比如它不是文字合約而是二進位合約,而且HTTP頭部採用HPACK進行壓縮,支援多工、伺服器發送等等。

二、屬性

1、二進位合約

HTTP/2 採用二進位格式傳輸資料,而非HTTP/1.x的文字格式設定。訊息頭和訊息體均採用二進位格式,並稱之為”幀“(Frame)。Frame二進位基本格式如下(摘自rfc7540#section-4.1):

+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+

之所以說是基本格式,是因為所有HTTP/2Frame都是由該基本格式來封裝,類似於TCP頭,目前有10個Frame,由Type欄位來區分,各個Frame都有自己的二進位格式,都封裝FramePayload中。

其中有兩個重要的Frame:HeadersFrame(Type=0x1)和Data Frame(Type=0x0),分別對應HTTP/1.1中的訊息頭(Header)和訊息體(Body),由此可見語義並沒有太大變化,而是文字格式設定變成二進位的Frame。二者的轉換和關聯如下圖(摘自《HighPerformance Browser Networking》):

_1

此外,HTTP/2中還有流(Stream)和訊息(Message)的概念,通過StreamIdentifier(即流ID)欄位來標識,流ID一樣的是同一個流,流中包含訊息,這個訊息對應HTTP/1.x的要求訊息(RequestMessage)或者回應訊息(ResponseMessage),訊息是通過幀(Frame)來傳輸的,回應訊息比較大,可能由多個DataFrame來傳輸。HTTP/2中流、訊息和幀的對應關聯如下圖(摘自《High Performance Browser Networking》):

2

2、頭部壓縮

HTTP/1.x 每次要求和回應,都會攜帶大量冗餘訊息頭資訊,比如Cookie和User Agent,基本一樣的內容,每次要求瀏覽器都會預設攜帶,這會浪費很多頻寬資源,也影響了速度。這是因為HTTP是無狀態合約,每次要求都必須附上所有資訊,從而導致了每次要求都帶上大量重複的訊息頭。

為此,HTTP/2做了優化,對訊息頭採用HPACK格式進行壓縮傳輸,並對訊息頭建立索引表,相同的訊息頭只傳送索引號,從而提高效率和速度。但付出的代價是用戶端和伺服器均維修一個索引表,在如今記憶卡值錢的年齡,這點空間換取時間還是非常值得的。

關於HPACK請參考RFC7541

3、多工

多工是指在一個TCP串連裡,用戶端和伺服器都可以同時傳送多個要求或者回應,對HTTP/1.x來說各個要求和回應都是有嚴格的次序要求,而在HTTP/2中,不用按照次序一一對應,而且並行的多個要求或者回應中任何一個要求阻塞了不會影響其他的要求或者回應,這樣就避免了“隊頭堵塞”。如下圖(摘自《High Performance Browser Networking》):
3

4、伺服器發送

伺服器發送(Server Push)是指在HTTP/2中伺服器未經要求可以主動給用戶端發送資源。例如服務端可以主動把圖片、JS和CSS 檔案發送給瀏覽器,而不需要瀏覽器解析HTML後再傳送這些要求。當瀏覽器解析HTML後這些需要的資源都已經在瀏覽器裡了,大大提高了網頁負載的速度。如下圖(摘自《High Performance Browser Networking》):

4

瀏覽器發起要求page.html這個網頁,這個網頁中參考了script.js和style.css,伺服器在回應page.html後順便發送了script.js和style.css這兩個檔案,這樣瀏覽器解析完page.html後發現參考的script.js和style.css已經在本地了,不需要再傳送要求了,這樣就節省了兩次要求和這兩次要求所花的網路時間,大大提高了網路效能和使用者體驗。

5、安全

HTTP的安全是由SSL/TLS來保障,也就是HTTPS,其實HTTP/2並不強制要求依賴SSL/TLS,但是,本期主流瀏覽器均只支援基於SSL/TLS的HTTP/2,況且在網路劫持日益猖獗的互連網環境下,HTTPS將是未來的趨勢,HTTP/2基於HTTPS也是未來的趨勢,而各大主流瀏覽器在實現HTTP/2之初均只支援SSL/TLS的HTTP/2,可見安全也是HTTP/2的重要屬性之一。

三、偵錯

從原理和目標上看HTTP/2和SPDY差不多,從Nginx官方代碼上看HTTP/2和SPDY的實現也差不多。Nginx官方代碼中已經移除了spdy模組的代碼,取而代之的是http2模組(ngx_http_v2_module)。

1、啟用

1.1、在編譯參數中上線http2模組(預設已經有ssl模組了):

# git clone https://github.com/alibaba/tengine.git
# cd tengine
# ./configure --prefix=/opt/tengine --with-http_v2_module
# make
# make install

1.2、生成測試憑證和私密金鑰

# cd /etc/pki/CA/
# touch index.txt serial
# echo 01 > serial
# openssl genrsa -out private/cakey.pem 2048
# openssl req -new -x509 -key private/cakey.pem -out cacert.pem
# cd /opt/tengine/conf
# openssl genrsa -out tengine.key 2048
# openssl req -new -key tengine.key -out tengine.csr
...
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:ZJ
Locality Name (eg, city) []:HZ
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Aliyun
Organizational Unit Name (eg, section) []:CDN
Common Name (e.g. server FQDN or YOUR name) []:www.tengine.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
...
# openssl x509 -req -in tengine.csr -CA /etc/pki/CA/cacert.pem -CAkey /etc/pki/CA/private/cakey.pem -CAcreateserial -out tengine.crt

1.3、設定http2

server {
listen443 ssl http2;
server_namewww.tengine.com;
default_typetext/plain;
ssl_protocolsTLSv1 TLSv1.1 TLSv1.2;
ssl_certificatetengine.crt;
ssl_certificate_key tengine.key;
ssl_ciphersEECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:EECDH+AES256:EECDH+3DES:RSA+3DESi:RC4-SHA:ALL:!MD5:!aNULL:!EXP:!LOW:!SSLV2:!NULL:!ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_cipherson;

location / {
return 200 "http2 is ok";
}
}

1.4、啟動tengine即可:

# /opt/tengine/sbin/nginx -c /opt/tengine/conf/nginx.conf
1.5、測試
先繫結/etc/hosts:
127.0.0.1 www.tengine.com
用nghttp工具測試:
jinjiu@j9mac ~/work/pcap$ nghttp 'https://www.tengine.com/' -v
[0.019] Connected
[0.043][NPN] server offers:
* h2
* http/1.1
The negotiated protocol: h2
[0.064] recv SETTINGS frame <length=18, flags=0x00, stream_id=0>
(niv=3)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):2147483647]
[SETTINGS_MAX_FRAME_SIZE(0x05):16777215]
[0.064] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=2147418112)
[0.064] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.064] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[0.064] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[0.064] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[0.077] send HEADERS frame <length=39, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
:method: GET
:path: /
:scheme: https
:authority: www.tengine.com
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/1.9.2
[0.087] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[0.087] recv (stream_id=13) :status: 200
[0.087] recv (stream_id=13) server: Tengine/2.2.0
[0.087] recv (stream_id=13) date: Mon, 26 Sep 2016 03:00:01 GMT
[0.087] recv (stream_id=13) content-type: text/plain
[0.087] recv (stream_id=13) content-length: 11
[0.087] recv HEADERS frame <length=63, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0)
; First response header
http2 is ok[0.087] recv DATA frame <length=11, flags=0x01, stream_id=13>
; END_STREAM
[0.087] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])

用chrome瀏覽器測試:
5

2>、抓包剖析

從抓包來學習HTTP/2格式是最好的辦法,但HTTP/2又是基於https的,也就是加密的,直接抓包看到的是密文,沒有意義,還好Wireshark提供解密https流量的辦法可以比較方便地偵錯HTTP/2。

2.1、先導出系統變數$SSLKEYLOGFILE,以OSX系統為例

#bash
echo "
export SSLKEYLOGFILE=~/ssl_debug/ssl_pms.log" >> ~/.bash_profile && . ~/.bash_profile

2.2、打開Chrome或者Firefox

#chrome
open /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
#firefox
open /Applications/Firefox.app/Contents/MacOS/firefox

用打開的Chrome或者Firefox瀏覽器打開https網站,比如:https://www.taobao.com
然後看看檔案~/ssl_debug/ssl_pms.log有沒有內容,有內容就可以用Wireshark解密https資料了。

2.3、Wireshark設定

Wireshark->Perferences...->Protocols->SSL

啟動抓包:
6

7

可見已經能得到HTTP/2的明文資料了。篇幅所限,在此不展開具體細節了,其他HTTP/2二進位合約細節請參考RFC7540

四、效能

測試機器設定:cache1.cn1,115.238.23.13, 16核Intel(R)Xeon(R) CPU L5630 @ 2.13GHz,48G記憶體,萬兆網卡
測試載入器:h2load
測試結果:

8

9

結論

1、無論是否keepalive,HTTP/2與SPDY/3.1效能相當,HTTP/2略優。
2、在size為1k、2k、4k測試結果中保留較低RT情況下QPS也較高,CPU沒有達到瓶頸,加大壓測用戶端數量後QPS有所提高,但RT變大,5xx也變多(這部份資料沒有給出,是測試時記錄的現象)。
在size為16k、32k、64k、128k、256k的測試結果中CPU達到瓶頸,隨著size變大,QPS降低,RT變高,CPU效能消耗較多的函數是gcm_ghash_clmul。
在size為512k時網卡達到瓶頸,CPU沒有達到瓶頸。
3、在開啟keepalive的情況下,HTTP/1.1的效能與HTTP/2的效能差距不是很大。但關閉keepalive時HTTP/2的效能比HTTP/1.1更好。

寫在最後

相比之前的傳輸協議,HTTP/2在底層方面做了很多優化。有安全、省時、簡化開發、更好的調整複雜網頁、提供快取利用率等顯著的優勢,各大公司也已經紛紛開始使用HTTP/2合約了。阿裡雲早在去年發佈的CDN6.0服務就已正式支援HTTP/2,存取速度最高可升階68%。不知不覺中,一個更安全、更可靠、更高速的年齡已經悄然而至。

相關產品:

  1. CDN
  2. 視訊直播
  3. 視訊點播
相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.