哔哩哔哩技术 08月26日
TLS 1.3 升级后 RTT 未达预期,排查 Nagle 算法问题
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

文章记录了作者在为服务升级 TLS 1.3 后,发现实际 RTT(往返时间)并未如预期般减少的排查过程。通过 Wireshark 分析数据包,发现额外的 RTT 主要发生在 TCP 层,具体是服务器端在收到客户端的 ACK 后才发送 Certificate Verify 和 Finished 包。排查发现,服务器开启了 Nagle 算法(tcp_nodelay off),该算法为了减少小数据包而增加了延迟。关闭 Nagle 算法后,TLS 握手时间成功缩短到 1 RTT,并显著降低了用户首次访问时延,国内可减少 10-40ms,海外甚至上百毫秒。

💡 TLS 1.3 旨在提升响应速度,将握手时间从 2 RTT 减少至 1 RTT,并增强安全性。然而,作者在升级后发现 RTT 未达预期,引发了深入的网络协议排查。

🕵️‍♂️ 通过 Wireshark 数据包分析,发现 TLS 握手过程中的额外延迟发生在 TCP 层,具体表现为服务器在收到客户端 ACK 后才发送关键的 Certificate Verify 和 Finished 包,这增加了 1 RTT。

🐌 问题根源指向了服务器上启用的 Nagle 算法(tcp_nodelay off)。Nagle 算法通过延迟发送小数据包来提高网络效率,但在时延敏感的应用场景下会适得其反,导致握手延迟。

✅ 关闭 Nagle 算法后,TLS 握手时间成功缩短至 1 RTT,服务器可以更及时地发送数据包,无需等待 ACK。此优化显著降低了用户首次访问时延,为服务带来了可观的性能提升。

原创 通用工程 2025-08-26 12:02 上海

作者在前段时间为某个服务升级支持了 TLS 1.3,然而在升级过程中发现 RTT 并没有按预期减少,所以进行了排查与记录,并分享给大家。

一. 前言

在正文开始之前,先简要介绍一下 TLS 1.3 与 TLS 1.2 有哪些主要差异:

    1. 更快的响应速度:

        a. TLS 完整握手时间从 2 RTT 减少为 1 RTT

        b. 增加 0 RTT 模式(以牺牲某些安全特性为代价)

    2. 更安全:

       a. 加密更多握手数据

       b. 更简洁更安全的加密套件:TLS 1.3 极大地简化了加密套件的设计,移除了不安全的加密算法。目前标准定义了 5 种加密套件,而非 TLS 1.2 中上百种复杂的可选组合,大幅降低了复杂性。

为了向大家提供更快、更安全的服务,笔者在前段时间为某个服务升级支持了 TLS 1.3,然而在升级过程中发现 RTT 并没有按预期减少,所以进行了排查与记录,并分享给大家。

二. 问题排查

笔者到测试 Server 的 RTT 约 36 ms,就当笔者升完服务,准备开开心心验收时,天塌了。打开浏览器一看 TLS 握手时长是 2 RTT,说好的 1 RTT 呢?

在反复确认了升级的软件版本没有异常,TLS1.3 相关配置没有异常之后,我们请出网络数据包分析利器 Wireshark。

乍看之下没有什么异常,TLS1.3 握手正常,也到了 HTTP 请求阶段。那我们再对比其他站点的请求看看。

仔细对比和分析后我们发现,多出来的 1 RTT 产生在第 12 个包,Server 端收到了 Client 的 Ack 后才发送了 Certificate Verify 和 Finished。所以我们判断可能和 TCP 层面的某些机制有关。

这里就引出一个问题,TCP 一次可以批量发送的数据受到哪些因素的影响:

1. 接收方窗口大小(RWND): 看抓包显示 Win 足够大,不会阻塞 Server 端传输

2. 接收和发送方的 MSS:都是 1460,正常范围

3. 拥塞控制:

a. 慢启动:根据 rfc6928  标准,初始窗口为 10。经确认我们服务器上也确实为 10。所以最大可以发送的数据量为 10 * MSS(1460)= 14 KB,Server 发送的数据量尚未达到初始窗口限制

b. 拥塞避免:比如丢包、或者 RTT 变长,看数据包判断没有触发

4. tcp_wmem: 由最小、默认、最大三个值组成,最小 4KB,  默认 16KB。考虑到测试节点没有压力,不会触发此限制。其次笔者尝试调大最小值做验证,依然没有解决问题

5. 其他因素

既然没能直接从数据包中推测出原因,咱们就再上服务器找找原因,根据之前的推断笔者用 tcp 作为关键词搜了一下服务配置,发现了线索: 

    tcp_nodelay off

    这段代码开启了 Nagle 算法。翻阅 RFC896 我们可以发现 Nagle 算法是为了解决小数据包问题,比如下面这种情况:各种协议必要的头尾数据占 58 bytes,真正需要传输的数据只有 1 byte,有效载荷比不到 2%。

    于是 Nagle 算法通过一种自适应的方法来减少小数据包的数量,提升网络效率。其本质是通过增加时延来换取更高的有效载荷比

    Nagle 算法的核心内容可以概括为:不一下子把所有小分组都发出去,而是等到前一个小分组的 ACK 收到或者攒够一个 MSS 大小再一起发

    Nagle 算法的规则:

      满载的数据包,允许发送

      包含 FIN,允许发送

      TCP_NODELAY 被设置,允许发送

      所有送的小数据包(长度小于 MSS)都被确认了,允许发送

      上述条件都未满足,但发送了超时(一般为 200 ms),则立即发送

    根据上述规则,我们可以看到 Server 发送的序号为 9 和 12 的都是未满载的数据包,所以 12 号包是等 Server 收到了 Client 对 9 号包的 Ack 后才发送的。这就增加了 1 RTT。

    Nagle 算法提出于 1984 年,那时的带宽、数据包处理能力都远不如今天。而在当前环境下,对于时延敏感的应用,通常建议关闭 Nagle 算法。

    经确认 Nagle 算法并不适合我们现在的场景,所以关闭 Nagle 算法后再做验证,TLS 握手时间果然只有 1 RTT。看数据包 Serever 端的 Certificate Verify 和 Finished 包也不需要等 Client 的 Ack 就直接发送了。

    至此问题已圆满解决。我们已将上述优化上线,可将国内用户首次访问时延减少 10 ~ 40ms,海外最高减少上百毫秒。

    咱们再回过头来仔细看一下 TLS 1.3 的握手流程,会多一层理解:1 RTT 只是 TLS 交互逻辑上的,真正端到端的交互时间还受到底层协议比如 TCP 的影响。

    三. 结语

    这次问题的排查过程让笔者对网络协议的实际行为有了更深入的理解。同时笔者也从基础的网络知识中受益颇多,所以将整个过程整理分享出来,希望也会对你有所帮助。

    推荐阅读:

    -End-

    作者丨House

    开发者问答

    大家还有过哪些有趣的性能优化或者 Debug 经历?

    欢迎在留言区分享你的见解~

    转发本文至朋友圈并留言,即可参与下方抽奖⬇️

    小编将抽取1位幸运的小伙伴获取JOJO的奇妙冒险 石之海 冷水杯

    抽奖截止时间:9月2日12:00

    如果喜欢本期内容的话,欢迎点个“在看”吧!

    往期精彩指路

    阅读原文

    跳转微信打开

    Fish AI Reader

    Fish AI Reader

    AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

    FishAI

    FishAI

    鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

    联系邮箱 441953276@qq.com

    相关标签

    TLS 1.3 RTT Nagle 算法 TCP 网络优化 性能排查 TLS 1.3 RTT Nagle Algorithm TCP Network Optimization Performance Troubleshooting
    相关文章