閱讀783 返回首頁    go 技術社區[雲棲]


阿裏雲 CDN HTTPS 最佳實踐——TLS record size(五)

原理

TLS 協議由兩層協議組成:TLS 握手協議和 TLS 記錄協議(TLS Record),TLS Record 協議在 TLS 握手協議之下。下麵是 SSL/TLS 的分層結構:

https5_1

所有的 TLS 上層數據(包含 TLS 握手協議消息以及更上層的應用協議數據)都由 TLS Record 來封裝和傳輸。下麵是 TLS Record 協議的消息封裝流程:

https5_2

一個消息會在 TLS Record 協議層被分段,然後對每個分段分別壓縮(已廢棄)和加密,最後加上 TLS Record 協議頭再通過網絡層發送出去,在 Wireshark 中可以看到:

https5_3

可以看出 TLS/SSL 數據加解密是基於分段的,接收方收到一個完整的分段就可以解密,如果分段過大,那接收方必須要等到接收完整個分段的數據才能解密,當網絡不好出現丟包、擁塞、重傳等等情況下會嚴重影響時延,如果分段過小,頭部負載比重就會較大,影響吞吐率。所以,怎麼分段就比較關鍵,也就是 TLS Record Size 大小多少合適。這就涉及到兩個重要的指標:時延和吞吐率。

  1. 如果 TLS Record Size 設置較大
    假如超過了 MTU,一個分段會被 TCP 層再次分段,拆分成多個包發送,那麼時延也相應地增大,但由於記錄協議頭占比很小,吞吐率也增大。
  2. 如果 TLS Record Size 設置較小
    一個分段在 TCP 層沒有被再次分段,由一個包發送出去,時延會比較小,但吞吐率也會下降。

所以,對時延敏感的域名,TLS Record Size 建議設置為略小於 MTU 的大小(粗算:MTU - TLS Record Header Length - TCP Header Length - IP Header Length)。對吞吐率敏感的域名,TLS Record Size 建議設置為 16k(上限)。如果同時兼顧時延和吞吐率的話,建議設置為 8k (經驗值)。

但是,TCP 有擁塞控製機製,在 TCP 連接剛開始的慢啟動階段,擁塞窗口會比較小,這時較大的 TLS Record Size 會導致 TLS Record 片段被 TCP 分成多個包來發送,從而導致時延較大,可能就會影響網頁的首屏時間。在整個 TCP 數據傳輸過程中,可能啟動擁塞避免算法,也可能遇到數據丟失和重傳的情況,然後又重新進入慢啟動階段。

因此,更好的做法是動態調整 TLS Record Size 的大小,而不是使用固定的值。在 TCP 連接初期使用較小的值,等傳輸速度上來之後再使用更大的值。

實現

nginx 本身支持 TLS Record Size 配置,但不支持動態調整,Cloudflare 實現了該功能(patch)。其算法原理是:

# 關鍵配置
ssl_dyn_rec_enable      on;
ssl_dyn_rec_size_lo     1369;
ssl_dyn_rec_size_hi     4229;
ssl_dyn_rec_threshold   40;
ssl_dyn_rec_timeout     1000ms;
  1. 對於一個新 TCP 連接,使用較小的 TLS Record Size 值(對應指令:ssl_dyn_rec_size_lo,默認值:1369)。
  2. 發送 40 個記錄(對應指令:ssl_dyn_rec_threshold,默認值:40)之後,將 TLS Record Size 值調大到 4229(對應指令:ssl_dyn_rec_size_hi,默認值:4229)。
  3. 發送 80 個記錄(2倍 threshold)之後,將 TLS Record Size 值調大到 16k(對應指令:ssl_buffer_size,默認值:16k)。
  4. 如果兩次數據發送間隔超過 1000 ms,則將 TLS Record Size 值調小到 1369,然後重新從步驟 1 開始。

Tengine 也采用了 Cloudflare 的方式,並將這些配置項通過 lua ffi 接口的方式,讓其在 lua 中可以動態設置,這樣便可以很方便地在 CDN 配置管理後台根據域名的實際情況來動態配置了。CDN 配置管理後台配置界麵截圖如下(該功能沒有開放到 CDN 用戶控製台):

https5_4

最後更新:2017-11-21 17:33:42

  上一篇:go  [從C到C++] 1.3 C++布爾類型(bool)
  下一篇:go  INTERSPEECH 2017係列 | 語音合成技術