tcp_nodelay on的作用是禁用nagle算法,使小数据包立即发送、不等待ack或攒包,但仅在长连接、响应≤1kb、后端已flush的精准场景下生效,须配置于location或upstream块中并配合keepalive、proxy_http_version 1.1等条件。

tcp_nodelay on 的作用很直接:关掉 Nagle 算法,让小数据包写完就发,不等 ACK、不攒包。但它不是“一开就灵”的开关,必须在对的路径、配对的条件下才真正起效。
只对长连接 + 小响应 + 高频交互场景有效
Nagle 算法只在连接持续存在、又有多个小块数据待发时才会“卡住等一等”。所以它只帮得上这些情况:
- WebSocket 升级后的连接(如
/ws),推送心跳帧、指令、行情更新(几十~几百字节) - SSE 接口(如
/api/events),流式发送data: {...}\n\n类短消息 - 轻量 API(如
/health、/status、/api/notify),返回 ≤1KB 的 JSON 或空响应 - Nginx 直接服务的小静态资源(如
favicon.ico、manifest.json、app.jschunk),前提是走 HTTP/1.1 keep-alive
短连接、大文件、代理转发到后端的链路——这些场景下 tcp_nodelay 基本不起作用。
必须放在 location 或 upstream 块里,不能全局开tcp_nodelay 是连接级行为,只影响 Nginx 与客户端之间的 TCP 连接。它在 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 或实时 API:
location /api/events { proxy_pass http://backend; tcp_nodelay on; tcp_nopush off; # 避免零拷贝缓冲干扰低延迟 } - 静态资源服务(JS/CSS/ico):
location ~* \.(js|json|ico|svg|png)$ { root /var/www/app; tcp_nodelay on; }
避开几个常见“失效组合”
光写 tcp_nodelay on 很可能白配:
- 同时启用
sendfile on但没配tcp_nopush on:tcp_nodelay在零拷贝路径下仍可生效,但若tcp_nopush on也开着,两者逻辑冲突,内核会优先执行tcp_nodelay;不过更稳妥的做法是——对小资源服务,保留sendfile on; tcp_nopush on; tcp_nodelay on;三件套,它们分工明确:tcp_nopush合并头+体发整包,tcp_nodelay保证最后一块不满的数据立刻发出 - 后端没 flush:Node.js 要调
res.flush(),Go 要用flusher.Flush(),否则数据卡在应用层缓冲区,Nginx 根本看不到 - 客户端未复用连接:检查请求头是否有
Connection: keep-alive,或用ss -i 'dst <client_ip>:80'</client_ip>看连接是否复用、是否有nodelay标志
验证是否真生效,别信配置信抓包
配置 reload 后,运行:
ss -tin 'dst <client_ip>:80' | grep nodelay</client_ip>
有输出说明已启用。再配合浏览器 DevTools 的 Network → WS Frames 查看消息端到端耗时是否稳定在 10–50ms(排除后端处理时间),才算闭环确认。











