<story><title>Golang disables Nagle&apos;s Algorithm by default</title><url>https://withinboredom.info/blog/2022/12/29/golang-is-evil-on-shitty-networks/</url></story><parent_chain><item><author>jrockway</author><text>Why does a congestionless network matter here?  Nagle&amp;#x27;s algorithm aggregates writes together in order to fill up a packet.  But you can just do that yourself, and then you&amp;#x27;re not surprised.  I find it very rare that anyone is accidentally sending partially-filled packets; they have some data and they want it to be sent now, and are instead surprised by the fact that it doesn&amp;#x27;t get sent now because their data doesn&amp;#x27;t happen to be too large to fit in a single packet.  Nobody is reading a file a byte at a time and then passing that 1 byte buffer to Write on a socket.  (Except... git-lfs I guess?)&lt;p&gt;Nagle&amp;#x27;s algorithm is super weird as it&amp;#x27;s saying &amp;quot;I&amp;#x27;m sure the programmer did this wrong, here, let me fix it.&amp;quot;  Then the 99.99% of the time when you&amp;#x27;re not doing it wrong, the latency it introduces is too high for anything realtime.  Kind of a weird tradeoff, but I&amp;#x27;m sure it made sense to quickly fix broken telnet clients at the time.</text></item><item><author>Terretta</author><text>Part of OPs point is &amp;#x27;most clients&amp;#x27; do not have an ideal congestionless&amp;#x2F;lossless network between them and, well, anything.</text></item><item><author>Philip-J-Fry</author><text>Yeah but Nagle&amp;#x27;s Algorithm and Delayed ACKs interaction is what causes the 200ms.&lt;p&gt;Servers tend to enable Nagle&amp;#x27;s algorithm by default. Clients tend to enabled Delayed ACK by default, and then you get this horrible interaction all because they&amp;#x27;re trying to be more efficient but stalling eachother.&lt;p&gt;I think Go&amp;#x27;s behavior is the right default because you can&amp;#x27;t control every server. But if Nagle&amp;#x27;s was off by default on servers then we wouldn&amp;#x27;t need to disabled Delayed ACKs on clients.</text></item><item><author>zamalek</author><text>From the bottom of the article:&lt;p&gt;&amp;gt; Most people turn to TCP_NODELAY because of the “200ms” latency you might incur on a connection. Fun fact, this doesn’t come from Nagle’s algorithm, but from Delayed ACKs or Corking. Yet people turn off Nagle’s algorithm … :sigh:</text></item><item><author>Philip-J-Fry</author><text>In my opinion, I think it&amp;#x27;s correct to be disabled by default.&lt;p&gt;I think Nagle&amp;#x27;s algorithm does more harm than good if you&amp;#x27;re unaware of it. I&amp;#x27;ve seen people writing C# applications and wondering why stuff is taking 200ms. Some people don&amp;#x27;t even realise it&amp;#x27;s Nagle&amp;#x27;s algorithm (edit: interacting with Delayed ACKs) and think it&amp;#x27;s network issues or a performance problem they&amp;#x27;re introduced.&lt;p&gt;I&amp;#x27;d imagine most Go software is deployed in datacentres where the network is high quality and it doesn&amp;#x27;t really matter too much. Fast data transfer is probably preferred. I think Nagle&amp;#x27;s algorithm should be an optimisation you can optionally enable (which you can) to more efficiently use the network at the expense of latency. Being more &amp;quot;raw&amp;quot; seems like the sensible default to me.</text></item></parent_chain><comment><author>avianlyric</author><text>&amp;gt; Nagle&amp;#x27;s algorithm aggregates writes together in order to fill up a packet.&lt;p&gt;Not quite an accurate description of Nagles algorithm. It only aggregates writes together if you already have in-flight data. The second you get back an ACK, the next packet will be sent regardless of how full it is. Equally your first write to the socket will always be sent without delay.&lt;p&gt;The case where you want to send many tiny packets with minimal latency doesn’t really make sense for TCP, because eventuality the packet overhead and traffic control algorithms will end up throttling your thought put and latency. Nagle only impact cases where you’re trying to TCP in an almost pathological manner, and elegantly handles that behaviour to minimise overheads, and associated throughput and latency costs.&lt;p&gt;If there’s a use case where latency is your absolute top priority, then you should be using UDP, and not TCP. Because TCP will always nobble your latency because it insists on ordered data delivery, and will delay just received packets if they arrive ahead of preceding packets. Only UDP gives you the ability to opt-out of that behaviour, and ensure that data is sent and received as quickly as your network allows, and lets your application decide for itself the handling of missing data.</text></comment>
<story><title>Golang disables Nagle&apos;s Algorithm by default</title><url>https://withinboredom.info/blog/2022/12/29/golang-is-evil-on-shitty-networks/</url></story><parent_chain><item><author>jrockway</author><text>Why does a congestionless network matter here?  Nagle&amp;#x27;s algorithm aggregates writes together in order to fill up a packet.  But you can just do that yourself, and then you&amp;#x27;re not surprised.  I find it very rare that anyone is accidentally sending partially-filled packets; they have some data and they want it to be sent now, and are instead surprised by the fact that it doesn&amp;#x27;t get sent now because their data doesn&amp;#x27;t happen to be too large to fit in a single packet.  Nobody is reading a file a byte at a time and then passing that 1 byte buffer to Write on a socket.  (Except... git-lfs I guess?)&lt;p&gt;Nagle&amp;#x27;s algorithm is super weird as it&amp;#x27;s saying &amp;quot;I&amp;#x27;m sure the programmer did this wrong, here, let me fix it.&amp;quot;  Then the 99.99% of the time when you&amp;#x27;re not doing it wrong, the latency it introduces is too high for anything realtime.  Kind of a weird tradeoff, but I&amp;#x27;m sure it made sense to quickly fix broken telnet clients at the time.</text></item><item><author>Terretta</author><text>Part of OPs point is &amp;#x27;most clients&amp;#x27; do not have an ideal congestionless&amp;#x2F;lossless network between them and, well, anything.</text></item><item><author>Philip-J-Fry</author><text>Yeah but Nagle&amp;#x27;s Algorithm and Delayed ACKs interaction is what causes the 200ms.&lt;p&gt;Servers tend to enable Nagle&amp;#x27;s algorithm by default. Clients tend to enabled Delayed ACK by default, and then you get this horrible interaction all because they&amp;#x27;re trying to be more efficient but stalling eachother.&lt;p&gt;I think Go&amp;#x27;s behavior is the right default because you can&amp;#x27;t control every server. But if Nagle&amp;#x27;s was off by default on servers then we wouldn&amp;#x27;t need to disabled Delayed ACKs on clients.</text></item><item><author>zamalek</author><text>From the bottom of the article:&lt;p&gt;&amp;gt; Most people turn to TCP_NODELAY because of the “200ms” latency you might incur on a connection. Fun fact, this doesn’t come from Nagle’s algorithm, but from Delayed ACKs or Corking. Yet people turn off Nagle’s algorithm … :sigh:</text></item><item><author>Philip-J-Fry</author><text>In my opinion, I think it&amp;#x27;s correct to be disabled by default.&lt;p&gt;I think Nagle&amp;#x27;s algorithm does more harm than good if you&amp;#x27;re unaware of it. I&amp;#x27;ve seen people writing C# applications and wondering why stuff is taking 200ms. Some people don&amp;#x27;t even realise it&amp;#x27;s Nagle&amp;#x27;s algorithm (edit: interacting with Delayed ACKs) and think it&amp;#x27;s network issues or a performance problem they&amp;#x27;re introduced.&lt;p&gt;I&amp;#x27;d imagine most Go software is deployed in datacentres where the network is high quality and it doesn&amp;#x27;t really matter too much. Fast data transfer is probably preferred. I think Nagle&amp;#x27;s algorithm should be an optimisation you can optionally enable (which you can) to more efficiently use the network at the expense of latency. Being more &amp;quot;raw&amp;quot; seems like the sensible default to me.</text></item></parent_chain><comment><author>tashbarg</author><text>It makes perfect sense if you consider the right abstraction. TCP connections are streams. There are no packets on that abstraction level. You’re not supposed to care about packets. You’re not supposed to know how large a packet even is.&lt;p&gt;The default is an efficient stream of bytes that has some trade-off to latency. If you care about latency, then you can set a flag.</text></comment>