OpenBSD 提供了關閉 Nagle's algorithm 的 sysctl 選項

看到「Demise of Nagle's algorithm (RFC 896 - Congestion Control) predicted via sysctl」這篇,OpenBSD 提供 sysctl 的選項直接關閉 Nagle's algorithm

The below changeset introduces sysctl net.inet.tcp.nodelay, which if set to 1 will simply cause TCP_NODELAY to be set on all TCP sockets.

不過裡面提到了 John Nagle 在 2015 年的時候有在 Hacker News 上面回覆 (id=10608356),大概介紹了一下背景,以及提出了他的看法:

That still irks me. The real problem is not tinygram prevention. It's ACK delays, and that stupid fixed timer. They both went into TCP around the same time, but independently. I did tinygram prevention (the Nagle algorithm) and Berkeley did delayed ACKs, both in the early 1980s. The combination of the two is awful. Unfortunately by the time I found about delayed ACKs, I had changed jobs, was out of networking, and doing a product for Autodesk on non-networked PCs.

然後翻了一下 John Nagle 的 Hacker News 帳號,看起來還蠻活躍的?常常 comment 一些東西...

Nagle's algorithm + TCP delayed acknowledgment

Hacker News 上看到「It's always TCP_NODELAY (brooker.co.za)」,在講常遇到的 TCP 效能問題,原文在「It’s always TCP_NODELAY. Every damn time.」這邊。

這邊提到了兩個 TCP 上的演算法,Nagle's algorithm 是把小封包積著,等到收到 ack 後再集中丟出去,這樣可以降低 TCP overhead;而 TCP delayed acknowledgment 則是在收到封包後要傳回的 ack 累積起來縮成一個 ack 丟出去 (或是等到 timeout),也是為了降低 TCP overhead。

可以看到這兩者的邏輯上雖然都是想要降低 TCP overhead,但方法剛好會打架。而且這兩個在 Linux 下系統預設都會啟用,所以成立條件不算少見,只要發送方的每個封包都比較小就容易觸發 (大封包的情況則是因為把 buffer 塞滿後就會丟出去,所以就不會延遲)。

這時候遇到 application protocol 很吃 latency 的設計時 (像是 ping-pong 類型的溝通),就容易撞到效能問題。

也因為很常見,所以 Hacker News 上也有好幾個人都有提到他們在工作上解過好幾次。

技術上的解決方案是關掉其中一個就可以了,但可以看到通常都是關掉 Nagle's algorithm (也就是設定 TCP_NODELAY),一方面因為大多數伺服器端的軟體都提供這個選項,改起來比較方便 (因為會被回報);另外一方面是是「趕快把封包送出去」會比「趕快收到 ack」來的有效率...

算是因為網路發展後產生的問題,以前只有 64kbps 專線 (8KB/sec) 的年代會斤斤計較這些東西:一個 IPv4 header 要 20 bytes,TCP header 也要 20 bytes,只傳 1 byte 的資料的確很傷頻寬。

但現在網路環境不太一樣了,尤其是文章裡面提到的環境通常是機房,1Gbps 與 10Gbps 算是常態,遇到 bandwidth 不會吃滿,但很需要 rps (request per second) 數量時,拿之前的演算法就容易中獎了...