tcp_nodelay on 用于禁用 Nagle 算法,使小数据包(如 HTTP 头、短 JSON、WebSocket 帧)在长连接中立即发送,降低交互延迟;但仅对 keepalive 连接且小响应体有效,需结合抓包或 ss -i 验证生效。

直接启用 tcp_nodelay on 并不能自动降低延迟,它只在特定条件下生效:必须配合长连接(keepalive)使用,且主要针对连续发送多个小响应的场景,比如 WebSocket、SSE、高频 API 流式响应等。
它解决什么问题:Nagle 算法带来的“攒包延迟”
Nagle 算法默认开启,它的逻辑是:如果前一个 TCP 包还没收到 ACK,又来了一个小数据块(比如几十字节的 JSON 或控制帧),就先不发,等 ACK 到了再一起发,或者等凑够一整包(MSS)。这能提升带宽利用率,但会引入 20–200ms 的等待延迟。
对交互类应用来说,用户发一条消息、点一次按钮、收一条通知,都希望“秒回”。这种延迟不可接受。tcp_nodelay 的作用就是关掉这个等待机制,让每个 write() 调用的数据立刻封装成包发出。
必须满足的前提条件
-
连接必须是长连接:需配置
keepalive_timeout(例如keepalive_timeout 65;),并确保客户端也复用连接(HTTP/1.1 默认支持,HTTP/2 原生支持);短连接(每次请求后立即断开)下 tcp_nodelay 完全无效。 - 响应体要足够小:大响应(如 >1KB 的 JSON)本身就会触发内核立即发送,Nagle 不起作用,也就无需 tcp_nodelay。
-
发生在启用了 keepalive 的连接上:该指令只在
http、server或location块中有效,且仅对已建立的长连接起效。
怎么配才真正起作用
不建议在全局 http 块盲目开启,应按接口类型精准启用:
- WebSocket 接口:
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on;
} - SSE 或实时消息流:
location /api/events {
proxy_pass http://backend;
tcp_nodelay on;
# 可同步关闭 tcp_nopush,避免缓冲干扰低延迟
tcp_nopush off;
} - 反向代理到后端服务时(如 Node.js/Go 微服务):
upstream api_backend {
server 127.0.0.1:3000;
keepalive 32;
}
...
location /api/ {
proxy_pass http://api_backend;
proxy_http_version 1.1;
proxy_set_header Connection '';
tcp_nodelay on;
}
怎么确认它真的生效了
光改配置不够,得验证:
- 用
nginx -t检查语法,重启后执行ss -i dst <client_ip>:80查看连接是否显示nodelay标志; - 抓包验证最可靠:用
tcpdump -i any port 80 -w delay.pcap,Wireshark 中观察连续小包之间的时间间隔——开启后应接近 0ms,关闭时常见 40ms 左右的固定延迟(Delayed ACK + Nagle 共同作用); - 对比压测结果:用
wrk -H "Connection: keep-alive" -d 10s http://host/api/stream,关注 p95/p99 延迟变化,而非平均值。


















