當前位置:
首頁 > 知識 > Web協議優化指南

Web協議優化指南

提到 Web 性能優化,那也就意味著我們遇到了很多性能方面的問題。

如上圖所示,看到這一行字,我相信大家的腦海里一定會浮現出很多的場景畫面,比如說無法接入網路,又比如說頁面一直在載入,或者說內容可能一直卡在 99% 載入不出來,包括視頻的卡頓、短視頻以及直播,還有從 WiFi 切到 4G 網路出現重新載入的情況,那遇到這麼多的 Web 問題,其主要原因是什麼呢?我進行簡單羅列一下,歸納為有以下兩種情況。

直接和頁面相關的頁面大小,頁面的元素類型的多少,也就是說一個頁面越大,元素越多,動態的交互越頻繁,那相應的性能可能就會受到更大影響。頁面優化問題也是前端優化的主戰場。

網路環境以及端配置,包括用戶手機硬體的性能、軟體的操作系統版本,也會對性能產生影響。而這兩個主要和運營商以及用戶的配置有關,也是我們很難施加影響的一部分。

網路協議

今天,我將著重介紹網路協議。網路協議是一個非常重要、非常關鍵、但又很容易被大家忽略的一個因素。那麼提到網路協議,我們會遇到或者會用到哪一些網路協議呢?

接下來,我以現在最主流的互聯網下一代 HTTP2 協議為例,來簡單地介紹一下。

加群六二三九六六八零六 免費領取前端學習資料,群里還有大神解答問題和交流

如上圖所示,Web 請求需要經過的協議棧。該圖左邊是客戶端,右邊是數據中心,或者說服務端。

請求從客戶端發出之後,首先會經過 HTTP1.1 協議。那為什麼標題是 HTTP2 請求,但卻提到的是 HTTP1.1?這是因為 HTTP2 雖然是一個全新的協議,但是它還是沿用了大部分 HTTP1.1 的語義。比如說 GET 請求、POST 請求,都是使用 HTTP1.1 的語義。對於頁面或者對於 JavaScript 來講,我們仍然使用著 HTTP1.1 的語義。HTTP1.1 下一層就到了 HTTP2, HTTP2 使用全新的幀控制語義,換句話說,HTTP2 frame 進行封裝 HTTP1.1 的語義,比如說 GET 請求,它通過使用 HTTP2 的 HEADERS 實現封裝;POST 請求的 body 數據使用 HTTP2 的 data frame 來實現封裝。然後到達 TLS 協議,傳輸加密層,那這裡為什麼會有加密呢?

其主要原因是 HTTP2 RFC7540 協議規定 HTTP2 有兩種實現,一種是 H2,強制使用 TLS 進行加密;另外一種是 H2C,這裡的 C 是 clear, 就是明文,不需要加密。雖然協議是這麼規定的,但是所有的主流實現,包括所有的瀏覽器、所有的操作系統、到目前為止都是使用 TLS 加密。也就是說,如果使用 HTTP2 就一定要使用 TLS 加密,所以在這過程中遇到 TLS 的問題。然後再往下是 TCP 層,再繼續往下是 IP 網路層,以及乙太網、運營商網路物理層,之後到達右邊服務端協議上。兩邊埠可以認為是對稱的,因此不再進行介紹。

那這麼多協議,我們應該需要關注哪一些呢?或者說更明確地說,對我們大部分 Web 應用開發者來講,我們需要關注哪一些呢? 上圖中白色虛線往上的部分是客戶端可以施加影響或者優化的一部分,即協議上提出的包括 TCP、TLS 協議,以及再往上的 HTTP。明確了我們需要優化的協議,那麼接下來我來分析一下他們都會有哪些問題。

HTTP1.1 的性能 HTTP1.1 的性能問題

加群六二三九六六八零六 免費領取前端學習資料,群里還有大神解答問題和交流

以現在使用最廣泛、歷史最悠久的 HTTP1.1 協議說起。

接觸 Web 開發的同學都知道,HTTP1.1 最大的性能問題就是單鏈路串列。當一個 TCP 鏈接上如果有多個請求。如上圖所示。請求只能一個接著一個發送,這是它最大的問題。

第二個問題是頭部未壓縮。頭部,尤其當 HTTP 請求 Cookie、Host,其瀏覽器型號都一樣,如果每次請求攜帶相同的信息,這顯然是重複的。這是冗餘,浪費帶寬,並且從性能問題上會影響用戶的訪問速度。為什麼呢?因為運營商的網路上下行帶寬嚴重不對稱,上行帶寬很可能只有下行帶寬 1/10 甚至小於 1/10,也就是說,若其帶寬有十兆或者一兆,那麼它上行鏈路可能只有 100K 甚至幾十 K。如果頭部平均大小是 1500 個位元組,其一次傳出可能有十個頭部,並且在帶寬層面會影響用戶訪問性能。因此在 3G、4G 的移動網路環境下,頭部未壓縮問題顯得更為重要。

HTTP1.1 的優化

優化的手段、優化的策略非常多,也非常有效,那麼有哪些呢?

概括來講,HTTP1.1 的優化方向主要是兩點。

第一點是增加並發連接數量;第二點是減少往外發出的請求數量。如上圖,不管是單域名多 TCP 連接,還是域名分片,使用多個域名都是為了提升並發連接的數量。需要注意的是並發連接不是並發請求。因為 HTTP1.1 嘗試在單鏈接上實現並發請求,但是失敗了。比如 pipelining,因為它存在隊頭阻塞。所以它只能通過提升並發連接的數量來提升用戶的訪問性能。此外,也有其他一些優化策略,包括緩存、CSS Sprite、data uri,圖片內聯等。其本質都是為了減少發出請求的數量,即將多個響應放在一個響應裡面返回,以此減少請求數量。

以上這些 HTTP1.1 優化策略和手段在 HTTP1.1 時代取得非常好的效果, 並且也行之有效。

HTTPS/HTTP2 加速 HTTP1.1 的淘汰

隨著 HTTPS 的全站趨勢越來越明顯, HTTP2 正式發布漸成主流,HTTP1.1 的優化策略隨之失效了。為什麼這麼說呢?

HTTPS 性能的一個特點或者說缺點是連接成本非常高,如果 HTTP1.1 使用增加並發連接的方式來提升性能,由於其連接成本很高,那麼並發連接的並發成本也就會高,反而降低了性能。

HTTP2 的特性是支持多路復用。在一個鏈接上允許發出多個請求,允許並發請求。那 HTTP1.1 減少請求數量就顯得有點多餘,相反地,有可能會降低緩存命中率,降低性能。

所以從這個層面來講, HTTP1.1 的優化策略有可能行不通,並且產生副作用的。

HTTP 與 HTTPS 的比較 HTTP VS HTTPS 連接成本

接下來我簡單介紹一下 HTTPS 的連接成本為什麼會高?從協議層面,它的連接成本高在哪裡?

如上圖,左邊圖是一次 HTTP1.1 的請求過程或者說是成本。HTTP1.1 請求非常簡單,只需要建立 TCP 連接,然後發送 HTTP 請求和響應就完成了。總過程只需要兩個 RTT 就可以實現一次 HTTP 請求。

右邊圖是一次 HTTPS 的請求。首先 HTTPS 通過三次握手建立 TCP 連接;然後發送 HTTP1.1 請求. 這裡為什麼是 HTTP1.1 的數據呢?因為如果讓用戶主動輸入 URL,大多數用戶不會主動輸入 HTTPS,比如說,訪問騰訊網, 他們不會輸入 https://www.qq.com, 而是輸入 www.qq.com 或者 http://www.qq.com。為了強制用戶使用 HTTPS 就會返回一個 302 跳轉,關於 302 跳轉,HTTPS 使用的埠是 443,HTTP 是 80;新的埠就必須重新建立一個新的 TCP 連接,這樣又多了一次 TCP 連接的建立過程;建立 TCP 連接之後,開始進行 TLS 握手階段。

TLS 握手有兩個階段,完全握手階段一,協商協議版本、密碼套件、請求證書、校驗證書;客戶端拿到證書之後即使證書的簽名沒有問題,證書時間也有效,但是仍然需要校驗證書的狀態,因為有可能存在主動撤銷證書的情況,證書的匙鑰也有可能被泄露或者說 CA 被攻擊,所以查詢證書狀態是必要的。查詢證書狀態就是 OCSP,在線證書狀態檢查,查詢證書狀態需要解析個 CA 的三點 DNS,又需要建立 TCP 連接,然後又需要建立包括 OCSP 的請求響應,通過 HTTP 請求完成,三次握手、狀態沒問題之後,開始進行 TLS 完全握手階段二,協商對稱密鑰,即非對稱密鑰交換計算;完成之後,整個 TLS 過程協商完畢,開始發送 HTTP 加密數據。至此達到第九個 RTT,相比 http1.1 多出 7 個 RTT,這是什麼概念呢?

未經優化的 HTTPS 速度明顯慢於 HTTP

如上圖,現在最好的 WiFi 網路環境下平均 RTT 是 70 毫秒,7 個 RTT 就是 490 毫秒,4G 是 100 毫秒,3G 是 200 毫秒, 7 個 RTT 就是一秒多鍾。且這僅僅是一次請求,一個頁面一般會有很多個請求,並且請求之間還可能有依賴,產生阻塞。以此情況下,一個頁面多出幾秒鐘是非常正常的現象,且該耗時僅僅為網路耗時;而由於協議的規定,它必須要進行網路交互,還包括很多其他的耗時,比如說計算耗時,證書校驗、密鑰計算、內容對稱的加解密等計算,由於移動端性能相對要弱,所以在這計算層面多出幾百毫秒也是非常正常的現象。

經過以上分析,我們可以得出一個基本結論,就是未經優化的 HTTPS 要比 HTTP 慢很多,那麼 HTTPS 是不是就是 slow,就是慢的意思呢?

為了找到慢的原因或者說找到性能的瓶頸,以上我們僅僅從網路協議理論進行分析,而事實上,在實驗環境下、業務真實環境下、用戶場景下面,它是不是還是這麼慢,又慢在哪裡呢?

為此,我們進行了兩個層面的分析。

線下模擬測試

第一個就是線下模擬測試。線下模擬測試主要針對移動端,因為移動端手機性能是流量越來越多的、都是往移動端傾斜。移動端有兩個特點,第一,手機屏幕比較小,查看數據或者查看頁面性能,調試日誌也不太方便;第二,不太方便運行數據的分析腳本、控制腳本。所以我們將手機和 PC 使用 USB 連接起來,通過遠程調試協議來控制手機上的瀏覽器來不斷的重複訪問我們所構造的不同的頁面。該頁面所涉及的元素一定是非常多的,不同的類型也都有。

因此我們進行線下模擬測試一定要自動化,靠人為實現是沒有效率的,並且也測試不了那麼多的頁面和場景。而且要注意數據的同比、環比,如果沒有,即使測試拿到了一百條數據,一千條數據也是不能說明問題的,因為數據誤差尤其多,周期性的同比、環比要求數據超過一萬條才認為它可能有一定的說明意義。

另外一個大誤差是 WiFi。即使是在洲際酒店、騰訊大廈,或者朗科大廈,使用的 WiFi 還是經常出現網路抖動的情況,這對數據、對協議的分析有巨大影響,因為協議很可能僅僅就是那麼一個 IT,那麼幾百毫秒的差異,在抖動的網路環境下很容易出現問題干擾結論。所以為了排除這些誤差,我們也經常將手機和 PC 用 USB 連接起來,繞開 WiFi 直接使用有線網路,因為有線相比無線,特別是 WiFi,要穩定非常多。

關於工具的話就是 traffic control,因為我們真實用戶的網路環境是千差萬別的。不同 IP,不同的帶寬,不同的丟包率,因此我們採用該工具來模擬在實驗室里模擬環境。線下模擬數據,顯然不能代表我們真實業務的性能。

線上業務速度數據採集

第二個部分是線上分析數據。

在服務端進行數據採集的方案有兩個優勢。

第一點它能採集到客戶端採集不到的數據,採集到更低層信息和業務信息。如上圖,左邊是客戶端,即可用手機、STW 或者是負載均衡器,右邊是業務伺服器。關於業務信息,通過 LB 和業務伺服器的交互可以獲得業務整體處理時間,這是客戶端拿不到的。第二點關於協議信息,包括 TCP 的 RTT、TCP 是否連接復用、是否 TLS SESSION 復用、 TLS 協議版本,密碼套件、握手時間以及非對稱密鑰交換計算時間,HTTP2 頭部壓縮比等,這些都是客戶拿不到的信息。

有些信息客戶端能採集到,但客戶端的開發成本很高,因為安卓有不同的版本,比如有 IOS、有 windows,需要針對不同操作系統進行開發,而在服務端只需要一次開發即可,將數據放到 COOKIE 里返回給客戶端,客戶端通過 JS 或者普通頁面就能獲取到信息,拿到信息之後,將協議相關的信息組合起來放到一條數據內統一上報到數據平台進行分析。

那麼拿出這麼多數據,我們數據平台如何去分析呢?

多維數據分析

如上圖,由於數據龐大,僅截取幾條進行分析。左邊是數據維度,比如 TCP-reuse 表示 TCP 連接復用,TLS1.2 表示 TLS 協議版本是 1.2;右邊是與用戶性能相關的監控指標,比如說開始載入時間,頁面可活動時間,業務處理時間等維度,這些維度也可互相組合併得出三四百個維度。如上圖所示,騰訊 X 五內核瀏覽器在 4G 網路下使用 HTTP2 並且是使用 TLS1.2 協議並且使用 ECDHE 並且沒有復用 TLS Session 的首屏時間是多少?通過多維度對比,我們很容易就可以區別出它慢的因素, X5 在 4G 是這麼多,那麼在 3G 下面是多少,WiFi 下面是多少呢?通過多維度綜合的對比就能從表面看出瓶頸在哪裡。

因此多維度數據分析,最終目的就是為了找到性能瓶頸以及速度優化方向,那麼有哪些優化方向呢?

Web 訪問速度優化方向

優化方向有三個。第一個協議;第二個資源;第三個用戶行為。

協議 TCP 速度優化

那麼協議層面如何進行優化呢?協議的最底層是 TCP,而 TCP 最顯而易見的性能問題是需要三次握手才能建立一個 TCP 連接,然後發送應用層數據,與普通握手相比,浪費一個 RTT。如上圖左邊是普通握手。每個 TCP 的連接需要建立握手,並且發送 SYN 包沒有任何運動組數據,RTT 就浪費了。

TFO 是 TCP FAST OPEN。在 SYN 包發出的同時將應用層數據發出來,然而它的前提是第一次建立握手、建立連接的時候也需要發 SYN 包,不同的是,伺服器返回 SYN+ACK 時會返回一個 COOKIE,在這之後用戶發起 TCP 連接,發出 SYN 包的同時會帶上這個 COOKIE,然後可以直接帶上 HTTP 數據。換句話說,在 SYN 包發出的同時將應用層數據一起發出來,減少了一個 RTT 對性能的影響。TCP FAST OPEN 性能是一個收益數據,我們發現 80 分的數據提升了將近一百毫秒。然而它的缺點是需要操作系統的支持,需要 IOS9+ 或者 linux kervel3.7+,並且不支持 Windows 系統。另一個優化方案是擁塞控制,將三個擁塞窗口增加到十個。

總的來說,在 TCP 協議層面來提升速度優化的空間有限,因為優化成本非常高,而高在哪裡呢?它需要操作系統、需要內核的支持,如果僅僅是服務端升級,我們支持與研發,其成本還能夠控制,但是最重要的是需要用戶的操作系統升級,需要廣大網路設備上的軟協議棧或者操作系統升級,而在這個層面部署的壓力非常大。所以 TCP 層面優化成本非常高。

TLS 速度優化 -session reuse

TLS 是加密層,加密層最大的問題是完全握手。關於完全握手,接觸過的同學應該很清楚它的 session ID,它的過程我就不做介紹了。

在這裡,我主要分享兩點。如上圖。第一點,關於 IOS Qzone 優化,通過 session id 握手時間大概能夠提升 50%;第二點,session ticket 的機制雖然更加先進,因為它不需要服務端提供緩存去提供內存存儲,發送 ticket,服務端進行校驗即可。而 session ID 需要提供內存進行存儲,然後查找到 session cache 是否命中,由於 IOS 不支持 session ticket,所以大家一定要注意通過分散式 session cache 來提升 IOS 的 session ID 的緩存命中率。很多場景是沒有辦法實現簡化握手的,比如說用戶第一次打開 APP、打開瀏覽器,又比如說用戶退出了再重新重啟瀏覽器,或者說把瀏覽器頁面關閉掉,再打開,都可能會導致 session cache 簡化握手無法實現,因為 session ticket 都是基於內存的,而不是存儲在硬碟裡面。

TLS 速度優化——False Start

針對完全握手的優化方法是 false start,即搶跑。與 TFO 思路類似,如上圖左邊是普通握手,必須要進行 TLS 的兩個 RTT 四次握手才能建立連接,發送應用層數據。false start 是在 clientKeyExchange 沒有交換的時候,即在完全握手的第二個階段將應用層數據一起發出來,提升了一個 RTT。那怎麼啟用 false start 呢?其實現在客戶端基本都已經支持了,如果服務端要啟用需要注意將支持 PFS(完美前向密碼)加密的演算法配置在前,比如說 ECDHE、DHE 演算法配置在前即可,並且其握手時間將提升 30%。

TLS 速度優化——OCSP StaplingOCSP Stapling。剛才提到的一些場景就是主動撤銷證書,所以一定要進行證書狀態的檢查,因為在某些情況下,單純地進行校驗證書的簽名、校驗證書的時間是發現不了證書的狀態,它需要更加實時的檢查。我們證書頒布 3 年,學校中間可能出問題,所以他會進行周期性的檢查。

他普通的過程與之類似, client hello 獲取到證書時,這過程中增加的 3 個 RTT 需要去 CA 站點請求 OCSP 的狀態和內容。如上圖,右邊是 OCSP Stapling,它的過程相當於伺服器代理實現了 CA 的證書狀態頒發的功能, 它提前向 CA 站點請求 OCSP 內容,並保存在本地伺服器端,然後在握手的同時,將像簽名的內容返回給客戶端,然後客戶端對該內容進行校驗。它不需要直接和 CA 站點進行交互,因此這樣看來 OCSP Stapling 減少了三個 RTT,效果應該非常明顯。

但是,事實上不是這樣的,為什麼?因為客戶端會對 OCSP 進行緩存,沒請求一次就可能可以緩存七天,也就是在這七天時期,如果用戶訪問該網站次數非常多,可能成千上萬次,因為一個頁面有非常多的請求,所以可能只有 1‰的概率來增加這三個 RTT。大家需要注意的,並不是一定就有這個效果。

TLS 速度優化——dynamic record size

現在來分析一下 dynamic record size,即記錄塊大小的動態的調整。

先簡單講解一下 TLS 協議層面的隊頭阻塞,即 head of line blocking 問題產生的背景,因為 TLS 協議傳輸的最基本單位是 record,一個記錄塊最大不能超過 16K,而一些服務端的實現,比如說 Nginx 最早期版本默認大小 16K。那麼 16K 會產生什麼情況呢?如果你中間丟了一個位元組,或者說由於 TCP 的籌碼丟了一個 segment,將導致這 16K 沒有辦法被校驗,就算接收到 15.99K 的數據,也沒有辦法處理,因為一個數據的丟失、一個包的丟失,導致整個 record 沒有辦法被處理。

那怎麼解決呢?方法有兩個。

第一個就是適當的調小 buffer,比如說改成 4K,不用實名制,即使丟失了也隻影響這 4k 數據,而不是 16K 數據。

第二個,借鑒 TCP 的 slow start 原理。cloud flare 提供一個 patch,在 TLS 連接剛剛建立的時候,由於不知道網路狀況以及擁塞情況,將 record 設置縮小,比如變成 1K, 在發送速度提升之後,再將 record size 設置為 16K。它大概是這麼個思路,也有開源代碼,大家有興趣的話可以了解一下。

剛才提到這些優化策略都是針對 TLS1.2 以及之前的版本。接下去介紹 TLS1.3 版本,這是一個革命性的、非常創新的、具有里程碑意義的協議。

加群六二三九六六八零六 免費領取前端學習資料,群里還有大神解答問題和交流

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT技術java交流 的精彩文章:

C語言還重要麼,學習有前途么?
我用Python爬取了全國4500個熱門景點,告訴你國慶哪兒最堵?
前端大神總結的HTML標籤,真的是太全了
快速學習C語言途徑,讓你少走彎路

TAG:IT技術java交流 |