全面解析HTTP/2:歷史、特性、調試、性能

摘要: 相比以前的傳輸協議,HTTP/2在底層方面作了不少優化。有安全、省時、簡化開發、更好的適應複雜頁面、提供緩存利用率等優點,阿里雲早在去年發佈的CDN6.0服務就已正式支持HTTP/2,訪問速度最高可提高68%。今天咱們從歷史、特性、調試、性能四個層面來全面解析HTTP/2javascript

寫在前面

超文本傳輸協議(英文:HyperText Transfer Protocol,縮寫:HTTP)是互聯網上應用最爲普遍的一種網絡協議。設計 HTTP 最初的目的是爲了提供一種發佈和接收 HTML 頁面的方法。經過 HTTP 或者 HTTPS 協議請求的資源由統一資源標識符(URI)來標識。css

雖然HTTP/1.1穩定運行了十多年了,但HTTP/2來勢洶洶,做爲技術工程師有必要學習一下HTTP/2。今天,阿里雲CDN安防技術專家金九將從歷史、特性、調試、性能四個層面,來全面解析HTTP/2,但願本文能夠給你帶來一些啓發。html


1、歷史

一、 HTTP/0.9
最先的原型,1991年發佈,該版本極其簡單,只支持 GET 方法,不支持 MIME 類型和各類 HTTP 首部等等。java

二、 HTTP/1.0
1996年發佈。HTTP/1.0在HTTP/0.9的基礎之上添加不少方法,各類 HTTP 首部,以及對多媒體對象的處理。nginx

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

任何格式的內容均可以發送。這使得互聯網不只能夠傳輸文字,還能傳輸圖像、視頻、二進制文件。這爲互聯網的大發展奠基了基礎。github

HTTP請求和迴應的格式也變了。除了數據部分,每次通訊都必須包括頭信息(HTTP header),用來描述一些元數據。chrome

能夠說,HTTP/1.0是對HTTP/0.9作了革命性的改變,但HTTP/1.0依然有一些缺點,其主要缺點是每一個TCP鏈接只能發送一個請求,發送數據完畢後鏈接就關閉,若是還要請求其餘資源,就得再新建一個鏈接。雖然有些瀏覽器爲了解決這個問題,用了一個非標準的Connection頭部,但這個不是標準頭部,各個瀏覽器和服務器實現有可能不一致,所以不是根本解決辦法。瀏覽器

3 、HTTP/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。

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

五、HTTP/2
HTTP/2是最新的HTTP協議,已於2015年5月份正式發佈, Chrome、 IE十一、Safari以及Firefox 等主流瀏覽器已經支持 HTTP/2協議。

注意是HTTP/2而不是HTTP/2.0,這是由於IETF(Internet Engineering Task Force,互聯網工程任務組)認爲HTTP/2已經很成熟了,沒有必要再發布子版本了,之後要是有重大改動就直接發佈HTTP/3。

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

HTTP/2不只優化了性能並且兼容了HTTP/1.1的語義,其幾大特性與SPDY差很少,與HTTP/1.1有巨大區別,好比它不是文本協議而是二進制協議,並且HTTP頭部採用HPACK進行壓縮,支持多路複用、服務器推送等等。


2、特性

一、二進制協議

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/2 Frame都是由該基本格式來封裝,相似於TCP頭,目前有10個Frame,由Type字段來區分,各個Frame都有本身的二進制格式,都封裝Frame Payload中。

其中有兩個重要的Frame:Headers Frame(Type=0x1)和Data Frame(Type=0x0),分別對應HTTP/1.1中的消息頭(Header)和消息體(Body),因而可知語義並無太大變化,而是文本格式變成二進制的Frame。兩者的轉換和關係以下圖(摘自 《High Performance Browser Networking》):

_1

此外,HTTP/2中還有流(Stream)和消息(Message)的概念,經過Stream Identifier(即流ID)字段來標識,流ID同樣的是同一個流,流中包含消息,這個消息對應HTTP/1.x的請求消息(Request Message)或者響應消息(Response Message),消息是經過幀(Frame)來傳輸的,響應消息比較大,可能由多個Data Frame來傳輸。HTTP/2中流、消息和幀的對應關係以下圖(摘自 《High Performance Browser Networking》):

2

二、頭部壓縮

HTTP/1.x 每次請求和響應,都會攜帶大量冗餘消息頭信息,好比Cookie和User Agent,基本同樣的內容,每次請求瀏覽器都會默認攜帶,這會浪費不少帶寬資源,也影響了速度。這是由於HTTP是無狀態協議,每次請求都必須附上全部信息,從而致使了每次請求都帶上大量重複的消息頭。

爲此,HTTP/2作了優化,對消息頭採用HPACK格式進行壓縮傳輸,並對消息頭創建索引表,相同的消息頭只發送索引號,從而提升效率和速度。但付出的代價是客戶端和服務器均維護一個索引表,在現在內存不值錢的時代,這點空間換取時間仍是很是值得的。

關於HPACK請參考RFC7541

三、多路複用

多路複用是指在一個TCP鏈接裏,客戶端和服務器均可以同時發送多個請求或者響應,對HTTP/1.x來講各個請求和響應都是有嚴格的次序要求,而在HTTP/2中,不用按照次序一一對應,並且併發的多個請求或者響應中任何一個請求阻塞了不會影響其餘的請求或者響應,這樣就避免了「隊頭堵塞」。以下圖(摘自 《High Performance Browser Networking》):
3

四、服務器推送

服務器推送(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已經在本地了,不須要再發送請求了,這樣就節省了兩次請求和這兩次請求所花的網絡時間,大大提升了網絡性能和用戶體驗。

五、安全

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


3、調試

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

一、啓用

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.二、生成測試證書和私鑰

# 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.三、配置http2

server {
        listen       443 ssl http2; server_name www.tengine.com; default_type text/plain; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_certificate tengine.crt; ssl_certificate_key tengine.key; ssl_ciphers EECDH+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_ciphers on; location / { return 200 "http2 is ok"; } } 

1.四、啓動tengine便可:

# /opt/tengine/sbin/nginx -c /opt/tengine/conf/nginx.conf 1.五、測試 先綁定/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

二、抓包分析

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

2.一、先導出系統變量$SSLKEYLOGFILE,以OSX系統爲例

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

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.三、Wireshark設置

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

啓動抓包:
6

7

可見已經能獲得HTTP/2的明文數據了。篇幅所限,在此不展開具體細節了,更多HTTP/2二進制協議細節請參考RFC7540


4、性能

測試機器配置:cache1.cn1, 115.238.23.13, 16核Intel(R) Xeon(R) CPU L5630 @ 2.13GHz,48G內存,萬兆網卡
測試工具:h2load
測試結果:

8

9


結論

一、不管是否keepalive,HTTP/2與SPDY/3.1性能至關,HTTP/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沒有達到瓶頸。
三、在開啓keepalive的狀況下,HTTP/1.1的性能與HTTP/2的性能差距不是很大。但關閉keepalive時HTTP/2的性能比HTTP/1.1更好。


寫在最後

相比以前的傳輸協議,HTTP/2在底層方面作了不少優化。有安全、省時、簡化開發、更好的適應複雜頁面、提供緩存利用率等顯著的優點,各大公司也已經紛紛開始使用HTTP/2協議了。阿里雲早在去年發佈的CDN6.0服務就已正式支持HTTP/2,訪問速度最高可提高68%。不知不覺中,一個更安全、更可靠、更高速的時代已經悄然而至。

本文爲雲棲社區原創內容,未經容許不得轉載,如需轉載請發送郵件至yqeditor@list.alibaba-inc.com;若是您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至:yqgroup@service.aliyun.com 進行舉報,並提供相關證據,一經查實,本社區將馬上刪除涉嫌侵權內容。
原文連接
相關文章
相關標籤/搜索