系统与基础设施brooker.co.za
永远该用 TCP_NODELAY
It's always TCP_NODELAY
2024 — 2025,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这是 Marc Brooker 的经典网络博客文章,解释为什么在延迟敏感的应用中几乎总该设置 TCP_NODELAY:Nagle 算法为了减少小包而延迟发送,但它与 TCP 延迟 ACK 相互作用,可能造成约 200ms 的等待,严重伤害交互式应用。文章讨论这一组合问题的成因和应对方式。
为什么经久不衰:它把困扰无数工程师的“神秘延迟”讲清楚,而且结论至今适用于游戏、SSH、RPC 等场景,是排查网络延迟问题的常备参考。
HN 评论精选
Nagle 的历史前提已过时,主张默认开启 TCP_NODELAY。
Nagle 算法诞生于多点网络和 CSMA 的时代,如今以太网基本都是点对点,CSMA 早已不再必要。关掉 Nagle(设置 TCP_NODELAY)几乎总是合理的,应该成为默认行为。
anonymousiam查看英文原文
The Nagle algorithm was created back in the day of multi-point networking. Multiple hosts were all tied to the same communications (Ethernet) channel, so they would use CSMA (https://en.wikipedia.org/wiki/Carrier-sense_multiple_access_with_collision_detection) to avoid collisions. CSMA is no longer necessary on Ethernet today because all modern connections are point-to-point with only two "hosts" per channel. (Each host can have any number of "users.") In fact, most modern (copper) (Gigabit+) Ethernet connections have both ends both transmitting and receiving AT THE SAME TIME ON THE SAME WIRES. A hybrid is used on the PHY at each end to subtract what is being transmitted from what is being received. Older (10/100 Base-T) can do the same thing because each end has dedicated TX/RX pairs. Fiber optic Ethernet can use either the same fiber with different wavelengths, or separate TX/RX fibers. I haven't seen a 10Base-2 Ethernet/DECnet interface for more than 25 years. If any are still operating somewhere, they are still using CSMA. CSMA is also still used for digital radio systems (WiFi and others). CSMA includes a "random exponential backoff timer" which does the (poor) job of managing congestion. (More modern congestion control methods exist today.) Back in the day, disabling the random backoff timer was somewhat equivalent to setting TCP_NODELAY. Dumping the Nagle algorithm (by setting TCP_NODELAY) almost always makes sense and should be enabled by default.
Go 默认已开启 TCP_NODELAY,但文章仍值得读。
我在调试自己游戏项目的网络延迟时读到这篇文章,结果发现我的问题不是 TCP_NODELAY——我的后端是 Go 写的,而 Go 默认就设置了 TCP_NODELAY。不过文章本身,尤其是 Nagle 本人对问题的承认,仍然很有意思。
eieio查看英文原文
I found this article while debugging some networking delays for a game that I'm working on. It turns out that in my case it wasn't TCP_NODELAY - my backend is written in go, and go sets TCP_NODELAY by default! But I still found the article - and in particular Nagle's acknowledgement of the issues! - to be interesting. There's a discussion from two years ago here: https://news.ycombinator.com/item?id=40310896 - but I figured it'd been long enough that others might be interested in giving this a read too.
Nagle 与延迟 ACK 叠加造成 200ms 延迟;应关 Nagle 并在应用层自行缓冲。
核心问题是 Nagle 与 TCP 延迟 ACK 的相互作用:发送方因有未确认的 ACK 而不发小包,接收方又把 ACK 延迟以捎带在响应上,二者同时生效就会出现约 200ms 的“死锁”,对游戏、SSH、高频 RPC 是灾难。Nagle 省下的带宽如今很少值得这份延迟代价,交互或请求-响应协议几乎都该设 TCP_NODELAY=1。但关掉 Nagle 后若频繁 write 小数据,问题就转移到应用层:应在用户态用缓冲写入器把一条逻辑消息拼进一块内存,再一次系统调用发出。
drfignewton查看英文原文
I swear, it seems like I’ve seen some variation of this 50 times on HN in the past 15 years. The core issue with Nagle’s algorithm (TCP_NODELAY off) is its interaction with TCP Delayed ACK. Nagle prevents sending small packets if an ACK is outstanding, while the receiver delays that ACK to piggyback it on a response. When both are active, you get a 200ms "deadlock" where the sender waits for an ACK and the receiver waits for more data. This is catastrophic for latency-sensitive applications like gaming, SSH, or high-frequency RPCs. In modern times, the bandwidth saved by Nagle is rarely worth the latency cost. You should almost always set TCP_NODELAY = 1 for any interactive or request-response protocol. The "problem" only shifts to the application layer: if you disable Nagle and then perform many small write() calls (like writing a single byte at a time), you will flood the network with tiny, inefficient packets. Proper usage means disabling Nagle at the socket level but managing your own buffering in user-space. Use a buffered writer to assemble a logical message into a single memory buffer, then send it with one system call. This ensures your data is dispatched immediately without the overhead of thousands of tiny headers. Check the Linux tcp(7) man page for implementation details; it is the definitive reference for these behaviors.
波兰语“nagle”意为“突然”,与算法效果巧合地贴切。
有意思的是,波兰语里的“nagle”(发音不同)意思是“突然”或“一下子”,对 Nagle 算法来说贴切得惊人,但我几乎确定这纯属巧合。
dllthomas查看英文原文
Wildly, the Polish word "nagle" (pronounced differently) means "suddenly" or "all at once", which is just astonishingly apropos for what I'm almost certain is pure coincidence.
历次讨论
同类还值得读
TTY 揭秘(2008)
The TTY demystified (2008)
经典文章深入剖析了 Unix/Linux 中 TTY 子系统的工作原理,包括线路规程、终端驱动、信号与控制字符等机制。
系统与基础设施上首页 11 次 · 2009–2025linusakesson.net编辑精选为什么 GNU grep 这么快
Why GNU grep is Fast
FreeBSD 邮件列表上一篇广为流传的帖子,解释 GNU grep 为什么快:核心在于 Boyer-Moore 字符串搜索算法配合精心优化的内部循环和 I/O,让程序在搜索时“…
系统与基础设施上首页 9 次 · 2010–2022lists.freebsd.orgXplain:为普通人讲解 X11
Xplain – Explaining X11 for the rest of us
《Xplain》是作者(HN 用户 Jasper_)写的一系列 X11 长文,用他在浏览器中重建的 X11 绘图模型做交互演示,讲解 X11 的绘图模型与窗口系统设计。
系统与基础设施上首页 6 次 · 2013–2020magcius.github.io编辑精选旋风教程:为 Linux 创建极小 ELF 可执行文件(1999)
A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux (1999)
breadbox 写于 1999 年的经典教程,主题是如何为 Linux 手工构造并裁剪出体积极小的 ELF 可执行文件。
系统与基础设施上首页 6 次 · 2007–2025muppetlabs.comPostgreSQL 内部原理
The internals of PostgreSQL
《The Internals of PostgreSQL》是一本免费在线书籍,系统讲解 PostgreSQL 的内部实现,包括查询处理、并发控制、WAL、缓冲区管理等核心机制。
系统与基础设施上首页 5 次 · 2017–2025interdb.jp编辑精选