一惠险、描述
? ? ?HTTP/2大致可以分為兩部分:分幀層苗傅,即h2多路復用能力的核心部分;數(shù)據(jù)或http層班巩,h2的分幀層是基于幀的二進制協(xié)議渣慕,分幀的目的,為了將重要信息都封裝起來抱慌,讓協(xié)議的解析方可以輕松閱讀逊桦、解析并還原信息。 相比之下抑进, h1 不是基于幀的强经,而是以文本分隔。通過窗口大小調節(jié)寺渗,依賴樹構建匿情,維持首部信息的靜態(tài) / 動態(tài)表,壓縮 / 解壓縮首部信殊,優(yōu)先級調整(h2 允許客戶端多次調整單一請求的優(yōu)先級)炬称, 預先推送客戶端尚未請求的數(shù)據(jù)流 ,來縮短響應時間鸡号,調高頁面請求渲染效率转砖。
二、HttP2協(xié)議
2.1)連接
? ? ? 首先雙重確認客戶端支持h2鲸伴,客戶端會發(fā)送一個叫作connection preface(連接前奏)的魔法字節(jié)流該字節(jié)流用十六進制表示如下:0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a 解碼為ASCII是:PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n?這個字符串的用處是府蔗,如果服務器(或者中間網(wǎng)絡設備)不支持h2,就會產生一個顯式錯誤汞窗。這個魔法字符串會有一個SETTINGS幀緊隨其后姓赤。服務器為了確認它可以支持h2,會聲明收到客戶端的SETTINGS幀仲吏,并返回一個它自己的SETTINGS幀(反過來也需要確認)不铆,然后確認環(huán)境正常,可以開始使用h2裹唆。
如何判斷H2
? ? 在連接不加密的情況下誓斥,客戶端會利用 Upgrade 首部來表明期望使用 h2。如果服務器也可以支持 h2许帐,它會返回一個“101 Switching Protocols”(協(xié)議轉換)響應響應來接受升級請求劳坑。在101空內容響應終止后,服務端可以開始發(fā)送HTTP/2幀成畦。這些幀必須包含一個發(fā)起升級的請求的響應,第一個被服務端發(fā)送的HTTP/2幀是一個設置(SETTINGS)幀距芬。在收到101響應后涝开,客戶端發(fā)送一個包含設置(SETTINGS)幀的連接序言,為了避免不必要的延遲框仔,允許客戶端在發(fā)送客戶端連接序言之后立即發(fā)送其他額外的幀舀武,不需要等待收到服務端連接序言。不過需要注意的是离斩,服務端連接序言設置(SETTINGS)幀可能包含一些關于期望客戶端如何與服務端通信的所必須修改的參數(shù)银舱。在收到這些設置(SETTINGS)幀之后,客戶端應當遵守所有設置的參數(shù)如果不支持HTTP/2的服務端對請求返回一個不包含升級的報頭字段的響應捐腿。
如 果 連 接 基 于 TLS纵朋, 情 況 就 不 同 了。 客 戶 端 在 ClientHello 消 息 中 設 置 ALPN(Application-Layer Protocol Negotiation茄袖,應用層協(xié)議協(xié)商)擴展來表明期望使用 h2 協(xié)議操软,服務器用同樣的方式回復。如果使用這種方式宪祥,那么 h2 在創(chuàng)建 TLS 握手的過程中完成協(xié)商聂薪。
2.2)幀
? ? ? HTTP/2是基于幀 (frame)的協(xié)議。有了幀蝗羊,處理協(xié)議的程序就能預先知道會收到什么藏澳。基于幀的協(xié)議耀找,特別是h2翔悠,開始有固定長度的字節(jié),其中包含表示整幀長度的字段野芒,這樣一來蓄愁,實現(xiàn)和維護都會簡單很多,請求和響應可以交錯甚至多路復用狞悲,最大幀主體的絕對長度是 $2^{14}-1$ (16,383)字節(jié)撮抓,如果一個幀大小超過設定的限制,或者太小無法包含必須的基礎幀數(shù)據(jù)摇锋,這個端點必須發(fā)送一個幀大小錯誤(FRAME_SIZE_ERROR)丹拯。如果幀大小錯誤可能修改整個連接狀態(tài),必須作為一個連接錯誤處理荸恕,幀的結構如下:
前9個字節(jié)對于每個幀是一致的
h2協(xié)議中有10種不同的幀類型如下:
2.3 流
? ? ?可以將流看作在連接上的一系列幀乖酬,它們構成了單獨的HTTP請求和響應。如果客戶端想要發(fā)出請求融求,它會開啟一個新的流剑刑。然后,服務器將在這個流上回復双肤。這與h1的請求/響應流程類似施掏,重要的區(qū)別在于,因為有分幀茅糜,所以多個請求和響應可以交錯七芭,而不會互相阻塞。流ID用來標識幀所屬的流蔑赘±瓴担客戶端到服務器的h2連接建立之后,通過發(fā)送HEADERS幀來啟動新的流缩赛,如果首部需要跨多個幀耙箍,可能還發(fā)會送CONTINUATION幀(更多信息參見下面的附注欄“CONTINUATIONS幀”)。該HEADERS幀可能來自HTTP請求酥馍,也可能來自響應辩昆,具體取決于發(fā)送方。后續(xù)流啟動的時候旨袒,會發(fā)送一個帶有遞增流ID的新HEADERS幀汁针,流內發(fā)送幀的順序很重要。它們將按被接收的順序處理砚尽。特別是報頭及數(shù)據(jù)幀的順序語義上是有意義的施无。
2.3.1 流量控制?
h2提供了客戶端調整傳輸速度的能力,WINDOW_UPDATE幀用來指示流量控制信息必孤。每個幀告訴對方猾骡,發(fā)送方想要接收多少字節(jié)。當一端接收并消費被發(fā)送的敷搪,數(shù)據(jù)時兴想,它將發(fā)出一個WINDOW_UPDATE幀以指示其更新后的處理字節(jié)的能力,一個新建立的流標識符必須數(shù)值大于任何終端已經打開或者保留的流標識符购啄。規(guī)則適用于使用報頭幀打開的流以及使用推送承諾幀保留的流襟企。終端收到不規(guī)范的流標識符必須響應一個類型為協(xié)議錯誤(PROTOCOL_ERROR)的連接錯誤,流標識符不能被重復使用狮含。生存期長的連接可能導致流標識符可用范圍耗盡顽悼。客戶端不能新建流標識符時可以針對新流建立一個新的連接几迄。服務端不能新建流標識符時可以發(fā)送一個超時幀(GOAWAY)強制客戶端對新的流使用新的連接蔚龙。設置幀里面的SETTINGS_MAX_CONCURRENT_STREAMS參數(shù)來限制流的并發(fā)量。初始化流量控制大小是65,535字節(jié)映胁。
流量控制是有方向性的木羹,由接收端全權掌握。接收端可以選擇針對流及整個連接設置任意的窗口大小。發(fā)送端必須遵守接收端的流量控制限制坑填∨兹耍客戶端、服務端及中端代理作為接收者時都獨立的向外廣播他們各自的流量控制窗口脐瑰,作為發(fā)送者時遵守接收端的限制妖枚。每個新的流及整個連接的流量控制窗口初始值是65,535字節(jié),只有DATA幀受流量控制苍在。
2.3.2?優(yōu)先級
? ?在沒有多路復用的時候绝页,在發(fā)出對新對象的請求之前,需要等待前一個響應完成寂恬。有了 h2续誉,客戶端就可以一次發(fā)出所有資源的請求,服務端也可以立即著手處理這些請求初肉,在沒有多路復用的時候酷鸦,在它可以發(fā)出對新對象的請求之前,需要等待前一個響應完成朴译。h2通過流的依賴關系來解決這個問題井佑。通過HEADERS幀和PRIORITY幀,客戶端可以明確地和服務端溝通它需要什么眠寿,以及它需要這些資源的順序躬翁。
2.3.3??流依賴
每個流可以顯式依賴其他流。包含一個依賴偏好設置表示分配資源給特定的流而不是所依賴的流盯拱,不依賴任何流的流的流依賴為0x0盒发。
2.3.4??依賴權重
所有有依賴的流都會被分配一個1-256(含)的整數(shù)來標識權重,流的優(yōu)先級是通過使用優(yōu)先級幀改變的狡逢。設置一個依賴將使流變得依賴某個特定的父節(jié)點流宁舰。
2.4 服務端推送服務
如果服務器決定要推送一個對象,會構造一個PUSH_PROMISE幀奢浑,PUSH_PROMISE幀的首部塊與客戶端請求推送對象時發(fā)送的首部塊是相似的蛮艰。所以客戶端有辦法放心檢查將要發(fā)送的請求,如果客戶端對PUSH_PROMISE的任何元素不滿意雀彼,就可以按照拒收原因選擇重置這個流(使用RST_STREAM)壤蚜,或者發(fā)送PROTOCOL_ERROR(在GOAWAY幀中)。
2.5?首部壓縮
? ?HPACK(http://www.reibang.com/p/f44b930cfcac) 是種表查找壓縮方案徊哑,它利用霍夫曼編碼獲得接近 GZIP 的壓縮效率袜刷。Hpack
2.6 請求示例
https://www.akamai.com/,www.facebook.com莺丑,www.yahoo.com,https://akah2san.h2book.com/
三著蟹、性能的影響
3.1、延遲
影響因素:端點之間的距離 和傳輸?shù)慕橘|。
3.2萧豆、丟包
? ? ? ?如果網(wǎng)絡中傳輸?shù)臄?shù)據(jù)包沒有成功到達目的地奸披,就會發(fā)生丟包;這通常是由網(wǎng)絡擁堵造成炕横。丟包通過丟包總數(shù)與已發(fā)送包總數(shù)的比值來衡量源内。頻繁丟包會影響h2的頁面?zhèn)鬏敚饕且驗閔2開啟單一TCP連接份殿,每次有丟包/擁堵時,TCP協(xié)議就會縮減TCP窗口嗽交。
對于包含很多小型資源(365個卿嘲,每個2KB)的Web頁面,h2加載頁面的時間比h1更短夫壁。這是因為h1下(有6個TCP連接)服務器只能并行發(fā)送6個資源(由于隊頭阻塞)拾枣,而h2下多個流(stream)可以共用連接。進一步說盒让,隨著網(wǎng)絡條件變差梅肤,h1和h2下PLT都會增加;但是對h2的影響更值得注意邑茄,因為這是單連接架構造成的姨蝴。如果唯一的連接發(fā)生了丟包,所有工作都會受影響肺缕。
3.3左医、服務端推送
服務端推送讓服務器具備了在客戶端請求之前就推送資源的能力。測試表明同木,如果合理使用推送浮梢,頁面渲染時間可以減少20%~50%。盡管如此彤路,推送也會浪費帶寬秕硝,這是因為服務端可能試圖推送那些在客戶端已經緩存的資源,導致客戶端收到并不需要的數(shù)據(jù)。
3.4菌瘫、第三方資源
? ? ?第三方調用會讓網(wǎng)站變慢房蝉,第三方請求往往通過不同域名發(fā)送;由于瀏覽器需要解析DNS憋飞、建立TCP連接、協(xié)商TLS姆吭,這將嚴重影響性能榛做, 因為第三方資源在不同域名下,所以請求不能從服務端推送、資源依賴检眯、請求優(yōu)先級等h2特性中受益厘擂。這些特性僅是為請求相同域名下的資源設計的; 你無法控制第三方資源的性能锰瘸,也無法決定它們是否會通過h2傳輸刽严。
3.5、不利用H2性能的H1優(yōu)化經驗
3.5.1避凝、域名拆分
? ? ? 域名拆分是為了利用瀏覽器對每個域名開啟多個連接的能力舞萄,以便實現(xiàn)資源的并行下載,繞過h1的串行化下載的限制因為HTTP/2采取多路復用管削,所以域名拆分就不是必要的了倒脓。
3.5.2、資源內斂
資源內聯(lián)包括把JavaScript含思、樣式崎弃,甚至圖片插入到HTML頁面中,目的是省掉加載外部資源所需的新連接以及請求響應的時間含潘,因為這樣會損失更有價值的特性饲做,比如緩存。
3.5.3 遏弱、資源合并
資源合并意味著把幾個小文件合并成一個大文件盆均。它與內聯(lián)很相似,旨在省掉那些加載外部資源的請求響應時間腾窝,以及解碼/執(zhí)行那些資源所消耗的CPU資源缀踪。
3.5.4、生成精靈圖
? ? 目前虹脯,生成精靈圖仍是一種避免小資源請求過多的技術為了生成精靈圖驴娃,開發(fā)者把較小的圖片拼合成較大的圖片,然后用CSS選擇圖片中某個部分展示出來多路復用和首部壓循集,縮去掉了大量的請求開銷唇敞。
四、實現(xiàn)
4.1咒彤、桌面版
? ? ?如果需要建立一個新連接疆柔,而瀏覽器支持連接歸并,那么通過復用之前已經存在的連接镶柱,就能夠提升請求性能旷档。這意味著可以跳過TCP和TLS的握手過程,改善首次請求新域名的性能歇拆。
4.2鞋屈、移動端
4.3范咨、移動端應用支持
自從2015年6月XCode更新2之后,蘋果公司在iOS中提供了對h2的支持厂庇;默認情況下渠啊,在使用NSURLSession時,網(wǎng)絡傳輸安全模塊就會允許原生iOS應用充分利用h2協(xié)議权旷。對于安卓應用替蛉,它們需要使用兼容h2的第三方庫,比如OkHttp3拄氯,并且必須通過TLS連接到支持h2的Web服務器上躲查。
4.4、內容分發(fā)網(wǎng)絡
? ? ? 內容分發(fā)網(wǎng)絡(CDN)是反向代理服務器的全球性分布式網(wǎng)絡坤邪,它部署在多個數(shù)據(jù)中心熙含。CDN的目標是通過縮短與最終用戶的距離來減少請求往返次數(shù),以此為最終用戶提供高可用艇纺、高性能的內容服務,大多數(shù)主流CDN是支持HTTP/2的邮弹,雖然協(xié)議支持的完整程度以及功能特性會因廠商不同而有所差異黔衡。
五、調試
5.1腌乡、瀏覽器
? ? ? chrome://net-internals
5. 2盟劫、webpagetest
5.3、openssl
? ? ? echo | openssl s_client -connect? www.tdw.cn:443 -servername www.tdw.cn?
? ? -alpn spdy/2,h2,h2-14 | grep ALPN
? 5.4与纽、nghttp2
? ? ? nghttp -v -n --no-dep -w 14 -a -H "Header1: Foo" https://www.akamai.com
? 5.5侣签、curl
? ? ? curl -v --http2 https://akah2san.h2book.com/hello-world.html? -w
? 5.6、h2i
? ? ? h2i www.google.com
?5.7急迂、Wireshark
? ? ? tshark port 443 and host www.example.com