筆者在過去分析了諸多可以減少 HTTPS 傳輸延遲的方法,如分散式 Session 的複用;
啟用 HSTS,客戶端預設開啟 HTTPS 跳轉;採用 HTTP/2 傳輸協議;使用 ChaCha20-Poly1305 演算法減少移動端 CPU 運算時間等。
通過這些方法,可以在很大程度上優化 HTTPS 在傳輸上的延遲,給網站使用者帶來較好的訪問體驗。
最近筆者又在考慮通過動態調節 TLS Record Size 來減少 HTTPS 傳輸延遲。
TLS 與 TCP
TLS 協議是由記錄層(TLS Record Layer)和握手層(TLS Handshake Layer)組成的,記錄層處於協議的最底層,為 TLS 協議提供安全可靠的連線,為高層協議提供資料封裝、壓縮、加密等基本功能的支援。握手層協議處於記錄層協議之上,握手層協議的作用在真正的應用資料傳輸之前,可以使客戶端和伺服器互相進行身份認證,協商加密演算法以及生成加密金鑰。一般來說,最大的 TLS Record 的大小為 16KB,而每個 TLS Record 包含一個 5Byte 的頭部。
TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連線(連線導向)的、可靠的、 基於 IP 的傳輸層協議。
TLS 是建立在可靠的資料傳輸的基礎之上,執行在 TCP 層之上,一個 TLS Record Size 由多個 TCP 包組成,通過 WireShark 抓包可以看出,一個 TLS Record 大小為 16408 Byte ,被分為了 12 個 TCP 包。
△ WireShark 抓包
動態 TLS Record Size 調整原理
Nginx 預設的 ssl_buffer_size 大小為 16KB(不支援動態調整),這就是一個 TLS Record Size 的大小。舉例說明, 假如資原始檔的大小為 1600KB,那麼就會被拆分為 100 個 TLS Record 傳送到客戶端。
在傳輸過程中此時會出現這樣的問題:
1. TLS Record Size 越大,被拆分的 TCP 包會過多,在傳輸過程中,如果 TCP 出現丟包情況,那麼 TLS Record 到達客戶端的時間就會變長,而客戶端必須等到收到完整的 TLS Record 才能夠進行解密;TLS Record 及 TCP 包的關係如下圖所示:
△ 圖片來源:igvita.com
2. 如果 TLS Record Size 較小,則 TCP 丟包對 TLS Record 的影響就較小了,但是於此同時,TLS Record 頭部就變多了,可能還會降低連線的吞吐量。
綜上所述,可以知道切割過小的 Record Size 會產生額外的消耗;而切割過大的 Record Size 會導致延遲。筆者認為可以根據 TCP 視窗大小來合理調整 TLS Record 大小可以有效降低 HTTPS 傳輸時造成的延遲。
如何進行 Record Size 大小調整
根據以上的論點,我們可以得出這樣的結論:在 TCP 慢啟動的過程中,可以將 TLS Record Size 調整小點;因為這個過程中 TCP 連結的擁塞視窗(cwnd )較小,TCP 連結的吞吐量也較小;在 TCP 連線結束慢啟動之後,TLS Record 的大小可以增大一些,隨著時間的推移,最終將 TLS Record 的大小調整到最大(也即 16KB)。
大致的演算法規則為:
- 在新連線以及 TCP 慢啟動階段,將 TLS Record 大小調整為大約 1 個 TCP 包的大小;
- 在一定的階段,也即傳送一定數量的 Record Size 之後,採用較大的 TLS Record Size ;
- 隨著時間的推移,採用最大的TLS Record Size 大小,也即 16KB。
WireShark 抓包驗證
通過 WireShark 抓包,對這個過程進行驗證:
階段一:在剛開始,TLS Record Size 為 1393 Byte。
階段二:一段時間之後,TLS Record Size 為 4253 Byte。
階段三:最後,TLS Record Size 動態變為 16408 Byte。
上圖三個階段的抓包結果驗證了動態 TLS Record Size 的演算法規則,通過對動態調節 TLS Record Size 可以有效降低 HTTPS 傳輸時的延遲,為客戶帶來更好的體驗。
目前,又拍雲 CDN 平臺已經完全支援動態調整 TLS Record Size ,對網站速度有更高要求的朋友可以通過開啟又拍雲 CDN,來使用動態 TLS Record Size,讓網站傳輸速度更快,給使用者更好的體驗。
推薦閱讀: