為什么我的 TLS 1.3 多了一個(gè) RTT
一. 前言
在正文開始之前,先簡要介紹一下 TLS 1.3 與 TLS 1.2 有哪些主要差異:
1. 更快的響應(yīng)速度:
a. TLS 完整握手時(shí)間從 2 RTT 減少為 1 RTT

b. 增加 0 RTT 模式(以犧牲某些安全特性為代價(jià))
2. 更安全:
a. 加密更多握手?jǐn)?shù)據(jù)
b. 更簡潔更安全的加密套件:TLS 1.3 極大地簡化了加密套件的設(shè)計(jì),移除了不安全的加密算法。目前標(biāo)準(zhǔn)定義了 5 種加密套件,而非 TLS 1.2 中上百種復(fù)雜的可選組合,大幅降低了復(fù)雜性。
為了向大家提供更快、更安全的服務(wù),筆者在前段時(shí)間為某個(gè)服務(wù)升級(jí)支持了 TLS 1.3,然而在升級(jí)過程中發(fā)現(xiàn) RTT 并沒有按預(yù)期減少,所以進(jìn)行了排查與記錄,并分享給大家。
二. 問題排查
筆者到測試 Server 的 RTT 約 36 ms,就當(dāng)筆者升完服務(wù),準(zhǔn)備開開心心驗(yàn)收時(shí),天塌了。打開瀏覽器一看 TLS 握手時(shí)長是 2 RTT,說好的 1 RTT 呢?
圖片
在反復(fù)確認(rèn)了升級(jí)的軟件版本沒有異常,TLS1.3 相關(guān)配置沒有異常之后,我們請(qǐng)出網(wǎng)絡(luò)數(shù)據(jù)包分析利器 Wireshark。
圖片
乍看之下沒有什么異常,TLS1.3 握手正常,也到了 HTTP 請(qǐng)求階段。那我們再對(duì)比其他站點(diǎn)的請(qǐng)求看看。
圖片
仔細(xì)對(duì)比和分析后我們發(fā)現(xiàn),多出來的 1 RTT 產(chǎn)生在第 12 個(gè)包,Server 端收到了 Client 的 Ack 后才發(fā)送了 Certificate Verify 和 Finished。所以我們判斷可能和 TCP 層面的某些機(jī)制有關(guān)。
圖片
這里就引出一個(gè)問題,TCP 一次可以批量發(fā)送的數(shù)據(jù)受到哪些因素的影響:
1. 接收方窗口大小(RWND): 看抓包顯示 Win 足夠大,不會(huì)阻塞 Server 端傳輸
2. 接收和發(fā)送方的 MSS:都是 1460,正常范圍
3. 擁塞控制:
a. 慢啟動(dòng):根據(jù) rfc6928 標(biāo)準(zhǔn),初始窗口為 10。經(jīng)確認(rèn)我們服務(wù)器上也確實(shí)為 10。所以最大可以發(fā)送的數(shù)據(jù)量為 10 * MSS(1460)= 14 KB,Server 發(fā)送的數(shù)據(jù)量尚未達(dá)到初始窗口限制
b. 擁塞避免:比如丟包、或者 RTT 變長,看數(shù)據(jù)包判斷沒有觸發(fā)
4. tcp_wmem: 由最小、默認(rèn)、最大三個(gè)值組成,最小 4KB, 默認(rèn) 16KB。考慮到測試節(jié)點(diǎn)沒有壓力,不會(huì)觸發(fā)此限制。其次筆者嘗試調(diào)大最小值做驗(yàn)證,依然沒有解決問題
5. 其他因素
既然沒能直接從數(shù)據(jù)包中推測出原因,咱們就再上服務(wù)器找找原因,根據(jù)之前的推斷筆者用 tcp 作為關(guān)鍵詞搜了一下服務(wù)配置,發(fā)現(xiàn)了線索:
tcp_nodelay off這段代碼開啟了 Nagle 算法。翻閱 RFC896 我們可以發(fā)現(xiàn) Nagle 算法是為了解決小數(shù)據(jù)包問題,比如下面這種情況:各種協(xié)議必要的頭尾數(shù)據(jù)占 58 bytes,真正需要傳輸?shù)臄?shù)據(jù)只有 1 byte,有效載荷比不到 2%。
圖片
于是 Nagle 算法通過一種自適應(yīng)的方法來減少小數(shù)據(jù)包的數(shù)量,提升網(wǎng)絡(luò)效率。其本質(zhì)是通過增加時(shí)延來換取更高的有效載荷比
Nagle 算法的核心內(nèi)容可以概括為:不一下子把所有小分組都發(fā)出去,而是等到前一個(gè)小分組的 ACK 收到或者攢夠一個(gè) MSS 大小再一起發(fā)
Nagle 算法的規(guī)則:
- 滿載的數(shù)據(jù)包,允許發(fā)送
- 包含 FIN,允許發(fā)送
- TCP_NODELAY 被設(shè)置,允許發(fā)送
- 所有送的小數(shù)據(jù)包(長度小于 MSS)都被確認(rèn)了,允許發(fā)送
- 上述條件都未滿足,但發(fā)送了超時(shí)(一般為 200 ms),則立即發(fā)送
根據(jù)上述規(guī)則,我們可以看到 Server 發(fā)送的序號(hào)為 9 和 12 的都是未滿載的數(shù)據(jù)包,所以 12 號(hào)包是等 Server 收到了 Client 對(duì) 9 號(hào)包的 Ack 后才發(fā)送的。這就增加了 1 RTT。
圖片
Nagle 算法提出于 1984 年,那時(shí)的帶寬、數(shù)據(jù)包處理能力都遠(yuǎn)不如今天。而在當(dāng)前環(huán)境下,對(duì)于時(shí)延敏感的應(yīng)用,通常建議關(guān)閉 Nagle 算法。
經(jīng)確認(rèn) Nagle 算法并不適合我們現(xiàn)在的場景,所以關(guān)閉 Nagle 算法后再做驗(yàn)證,TLS 握手時(shí)間果然只有 1 RTT。看數(shù)據(jù)包 Serever 端的 Certificate Verify 和 Finished 包也不需要等 Client 的 Ack 就直接發(fā)送了。
圖片
圖片
至此問題已圓滿解決。我們已將上述優(yōu)化上線,可將國內(nèi)用戶首次訪問時(shí)延減少 10 ~ 40ms,海外最高減少上百毫秒。
咱們再回過頭來仔細(xì)看一下 TLS 1.3 的握手流程,會(huì)多一層理解:1 RTT 只是 TLS 交互邏輯上的,真正端到端的交互時(shí)間還受到底層協(xié)議比如 TCP 的影響。
圖片
三. 結(jié)語
這次問題的排查過程讓筆者對(duì)網(wǎng)絡(luò)協(xié)議的實(shí)際行為有了更深入的理解。同時(shí)筆者也從基礎(chǔ)的網(wǎng)絡(luò)知識(shí)中受益頗多,所以將整個(gè)過程整理分享出來,希望也會(huì)對(duì)你有所幫助。


























