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) 數量時,拿之前的演算法就容易中獎了...