首页/网络/协议速查/Nagle 算法与延迟确认的 40ms 坑
TCP 与 UDP54 条

Nagle 算法与延迟确认的 40ms 坑

Nagle 等「一个未确认小包」发出前的攒批,与接收侧延迟 ACK(最多 40ms)叠加时,会产生经典的 40ms 延迟尖刺。

协议速查网络更新于 2026-10-13

40 毫秒延迟是怎么来的

发送方的 Nagle 算法规定「未被确认的小包最多只有一个在路上」,其余小数据先攒着凑成更大的段;接收方的延迟确认策略又不急着回 ACK,倾向于等最多几十毫秒搭别的数据一起发。两者叠加就出现经典的延迟阶梯:应用写完一小段就等对端响应,而这一小段被 Nagle 压住,对端的确认又在等更多数据,双方互相等,延迟凭空多出几十毫秒。

基本信息

Nagle 算法发送方侧:同一时刻最多一个未被确认的小包在途,其余攒批
延迟确认接收方侧:不立即回 ACK,等一小段时间搭车发送,Linux 上由启发式策略决定
组合问题写、写、读模式下第二段小数据被压住,同时等对方的延迟确认,形成卡顿
常用开关TCP_NODELAY 置 1 即关闭 Nagle,对端无法控制本端行为
适用场景交易、游戏、RPC 等低延迟链路,批量吞吐场景则适合保留 Nagle

关闭 Nagle 的常见写法

关闭 Nagle 的常见写法
import socket
s = socket.create_connection(("api.example.com", 80))
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)   # 应用层关掉 Nagle,小包立即发出
s.sendall(b'{"a":1}')
# nginx 侧对应指令:tcp_nodelay on;    # 新版本默认即为 on,作用于客户端与上游连接
# 后端的 Java 服务通常在连接池上配置 TCP_NODELAY,或用 Netty 的 TCP_NODELAY 选项

现象与处置对照

现象原因处置
请求响应都是小包,耗时呈固定阶梯Nagle 与延迟确认叠加应用侧打开 TCP_NODELAY
只在传大文件时吞吐上不去窗口、拥塞控制或链路限制不要盲目关 Nagle,先看重传与窗口
关闭后包量明显上升、带宽利用率反而降小包变多,头部开销占比升高评估按包量计费的链路成本
延迟忽高忽低、无明显阶梯更像网络抖动或排队用抓包看时间差,别急着改套接字选项
延迟确认并不是固定 40 毫秒:Linux 用的是快速确认与延迟确认并存的启发式策略,实际等待时长取决于流量形态与内核版本,40 毫秒只是最常见量级下的典型上限。
关闭 Nagle 之后小包数量上升,在按包量或连接数计费的云环境里成本会变化,调优时应把延迟收益与账单、限速一起评估。

易错点

  • 只在一端调整就以为解决了问题:Nagle 在发送端、延迟确认在接收端,需要先判断延迟到底发生在哪一侧
  • 对所有场景一律关闭 Nagle,批量传输场景小包变多,吞吐与包量成本双双变差
  • 把 40 毫秒阶梯当成应用代码慢,反复优化业务逻辑却始终不生效,实际瓶颈在 TCP 选项
  • 用长连接又不开 TCP_NODELAY,请求量增大后延迟阶梯被放大,用户侧体感表现为随机卡顿

数据来源与参考

  • RFC 896(Nagle 算法)
  • RFC 9293 §3.7.4

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌