1. 程式人生 > >全面解析HTTP/2:歷史、特性、除錯、效能

全面解析HTTP/2:歷史、特性、除錯、效能

寫在前面

超文字傳輸協議(英文:HyperText Transfer 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請求和迴應的格式也變了。除了資料部分,每次通訊都必須包括頭資訊(HTTP header),用來描述一些元資料。

可以說,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。

# 4、SPDY


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

5、HTTP/2
HTTP/2是最新的HTTP協議,已於2015年5月份正式釋出, Chrome、 IE11、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進行壓縮,支援多路複用、伺服器推送等等。

二、特性

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/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

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 {
        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.4、啟動tengine即可:

# /opt/tengine/sbin/nginx -c /opt/tengine/conf/nginx.conf
1.5、測試
先繫結/etc/hosts:
127.0.0.1 www.tengine.com
用nghttp工具測試:
[email protected] ~/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 "\nexport 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%。不知不覺中,一個更安全、更可靠、更高速的時代已經悄然而至。

相關推薦

全面解析HTTP/2歷史特性除錯效能

寫在前面 超文字傳輸協議(英文:HyperText Transfer Protocol,縮寫:HTTP)是網際網路上應用最為廣泛的一種網路協議。設計 HTTP 最初的目的是為了提供一種釋出和接收 HTML 頁面的方法。通過 HTTP 或者 HTTPS 協議請求的資源由統一資源識別符號(URI)來標識。

HTTP/0.9到HTTP/2一文讀懂HTTP協議的歷史演變和設計思路

eight 結果 key 視頻 this sso單點登陸 會有 研究 patch 本文原作者阮一峰,作者博客:ruanyifeng.com。 1、引言 HTTP 協議是最重要的互聯網基礎協議之一,它從最初的僅為瀏覽網頁的目的進化到現在,已經是短連接通信的事實工業標準,最新版

安卓專案eclipse有用教程設定應用名字和圖示螢幕簽名真機除錯cleanlogcatjson解析

怎樣在安卓專案中。設定遊戲的應用名字和圖示? 我們在Androidproject的res資源目錄下。會看到3個drawable的目錄和一個values目錄。就是在這裡改動即可。

全面解析回溯法演算法框架與問題求解

#include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int* data; int is_a_solution(int a[],int k, int step); //void

Android開發JSON簡介及最全面解析方法(GsonAS自帶org.jsonJackson解析)

目錄 JSON簡介&解析方法介紹.png 定義 JavaScript Object Notation,JavaScript的物件表示法,是一種輕量級的文字資料交換格式。 作用 用於資料的標記、儲存和傳輸。 特點 輕量級的文字資料交換格式 獨立於語言和平臺 具有自我描述性 讀寫速度快,解析簡單 語法

【新功能前瞻】SpreadJS 純前端表格控制元件V12.2列印增強拖拽填充等六大特性

  作為一款備受華為、招商銀行、中國平安、蘇寧易購等行業專家和前端開發者認可的純 JavaScript 電子表格和網格功能控制元件,SpreadJS 致力於為企業提供更高效的表格資料處理手段,以及更為親切的類 Excel 使用體驗。 華為的技術工程師曾這樣評價SpreadJS:“簡單的一百多

javaScript之this全面解析(2)

mode undefined fin 全局對象 bar def rip 布爾 defined 在理解this的綁定過程之前,我們先來理解調用位置(不是聲明位置) ,最重要的是要分析調用棧(就是為了到達當前執行位置所調用的所有函數)。 我們關心的調用位置就在當前正在執行的函數

HTTP請求和響應2方法(Method)

trace 行處理 診斷 ack 中間 delete nds 最優 eas 方法表明了client希望server對資源運行的動作。經常使用的方法包含:GET、HEAD、POST、PUT、TRACE、OPTIONS和DELETE,每一個server能夠實現這些方法中

Linux 7個運行級別(0關機,停機模式1單用戶模式2多用戶模式3完整的多用戶文本模式4系統未使用,保留一般不用5圖形化模式6重啟模式)重置root密碼方法

oca alt 開機重啟 正常 說明 特殊情況 其中 ice root權限 init是Linux系統操作中不可缺少的程序之一。init進程,它是一個由內核啟動的用戶級進程。內核會在過去曾使用過init的幾個地方查找它,它的正確位置(對Linux系統來說)是/

《Flask web開發》筆記2模板---繼承bootstrap

only world use 可能 clas 似的 () 目前 div 前言:今天重新梳理了一下前端方面的知識,發現學習東西還是要用,不然忘得快,廢話不多說,開始!! 一.模板繼承 1.概念: 書上說,模板繼承,類似Python上的繼承; 其實個人覺得和所有繼承

WAF——針對Web應用發起的攻擊,包括但不限於以下攻擊類型SQL註入XSS跨站Webshell上傳命令註入非法HTTP協議請求非授權文件訪問等

授權 文件訪問 http協議 火墻 針對 str sql 包括 fire 核心概念 WAF Web應用防火墻(Web Application Firewall),簡稱WAF。 Web攻擊 針對Web應用發起的攻擊,包括但不限於以下攻擊類型:SQL註入、XSS跨站、Websh

T4系列文章之2T4工具簡介調試以及T4運行原理(轉)

技術分享 animate 等了 edit uml 執行 為我 direct 感覺 出處:http://www.cnblogs.com/damonlan/archive/2012/01/12/2320429.html 一、前言 經過第一篇,我想大家現在對T4有了基本

nginx.conf配置文件解析(httpserverlocation proxy_pass)

static 如果 優先 max 關閉 logs ima use 顯示不正常 nginx.conf配置文件解析(http、server、location) 標簽: nginxnginx-conf 2017-04-26 20:10 1031人閱讀 評論(0)

Zabbix 3.4.6 新特性歷史數據支持 Elasticsearch

openssl security sql rod start postgre pre first sim 一、升級 cURL註:先升級 cURL,然後在安裝 Zabbix Server,否則報如下錯誤:cannot initialize history storage: c

MongoDB-2MongoDB添加刪除修改

一個數 日期 find quantity database dto 時間戳 創建 例子 一、簡介 MongoDB是一個高性能,開源,無模式的文檔型數據庫,是當前NoSQL數據庫產品中最熱門的一種。數據被分組存儲在數據集中,被稱為一個集合(Collenction)

Shell基礎介紹歷史命令命令不全和別名通配符輸入輸入重定向管道發和作業控制

基礎 一個 直接 1.5 寫到 否則 shel attr tle Shell的介紹 zsh、ksh(yum list |grep zsh 進行查看,然後可以相應的進行安裝) 命令歷史1. /root/.b

Android全面解析 熟悉而陌生 的Application類使用

screen 存儲 程序啟動 兩個 com 完全 @override mat 例子 前言 Applicaiton類在 Android開發中非常常見,可是你真的了解Applicaiton類嗎? 本文將全面解析Applicaiton類,包括特點、方法介紹、應用場景和具體使用,

學習之路(二)淺談bash及其特性,命令歷史以及用戶管理及權限,shell的類型

bash 管理權限 過了一周了,進度似乎有點懈怠,不過過了周末重整旗鼓啦shell(外殼)GUI:Gnome,KDE,xfceCLI:sh,csh,ksh,bashbash(父進程)-----bash(子進程)他們相互獨立彼此不知命令歷史:historybash支持的引號:‘ ’命令替換(鍵盤~的按鍵

shell特性通配符輸入輸出重定向,命令歷史

comm 解釋 指令 alias命令 命令補全和別名 zsh 開頭 命令 匹配 一:shell介紹 shell是一個命令解釋器,提供用戶和機器之間的交互,支持特定語法,每個用戶都可以有自己特定的shell,centos默認為bash,還有zsh,ksh等。 二:命令歷史 h