nginx 的 tcp_nopush 和 tcp_nodelay

TCP_NODELAY 和 TCP_CORK,
這兩個選項都對網絡連接的行爲具有重要的作用。許多UNIX系統都實現了 TCP_NODELAY選項,但是,TCP_CORK則是Linux系統所獨有的 而且相對較新;它首先在內核版本2.4上得以實現。此外,其他UNIX系統版本也有功能類似的選項,值得注意的是,在某種由BSD派生的系統上的 TCP_NOPUSH選項其實就是TCP_CORK的一部分具體實現。
TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle 化”,Nagle化在這裏的含義是採用Nagle算法把較小的包組裝爲更大的幀。 John Nagle是Nagle算法的發明人,後者就是用他的名字來命名的,他在1984年首次用這種方法來嘗試解決福特汽車公司的網絡擁塞問題(欲瞭解詳情請參 看IETF RFC 896)。他解決的問題就是所謂的silly window syndrome ,中文稱“愚蠢窗口症候羣”,具體含義是,因爲普遍終端應用程序每產生一次擊鍵操作就會發送一個包,而典型情況下一個包會擁有一個字節的數據載荷以及40 個字節長的包頭,於是產生4000%的過載,很輕易地就能令網絡發生擁塞,。 Nagle化後來成了一種標準並且立即在因特網上得以實現。它現在已經成爲缺省配置了,但在我們看來,有些場合下把這一選項關掉也是合乎需要的。
現 在讓我們假設某個應用程序發出了一個請求,希望發送小塊數據。我們可以選擇立即發送數據或者等待產生更多的數據然後再一次發送兩種策略。如果我們馬上發 送數據,那麼交互性的以及客戶/服務器型的應用程序將極大地受益。例如,當我們正在發送一個較短的請求並且等候較大的響應時,相關過載與傳輸的數據總量相 比就會比較低,而且,如果請求立即發出那麼響應時間也會快一些。以上操作可以通過設置套接字的TCP_NODELAY選項來完成,這樣就禁用了Nagle 算法。
另外一種情況則需要我們等到數據量達到最大時才通過網絡一次發送全部數據,這種數據傳輸方式有益於大量數據的通信性能,典型的應用就是文 件服務器。應用 Nagle算法在這種情況下就會產生問題。但是,如果你正在發送大量數據,你可以設置TCP_CORK選項禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就讓我們仔細分析下其工作原理。
假設應用程序 使用sendfile()函數來轉移大量數據。應用協議通常要求發送某些信息來預先解釋數據,這些信息其實就是報頭內容。典型情況下報頭很 小,而且套接字上設置了TCP_NODELAY。有報頭的包將被立即傳輸,在某些情況下(取決於內部的包計數器),因爲這個包成功地被對方收到後需要請求 對方確認。這樣,大量數據的傳輸就會被推遲而且產生了不必要的網絡流量交換。
但是,如果我們在套接字上設置了TCP_CORK(可以比喻爲在管 道上插入“塞子”)選項,具有報頭的包就會填補大量的數據,所有的數據都根據大小自動地 通過包傳輸出去。當數據傳輸完成時,最好取消TCP_CORK 選項設置給連接“拔去塞子”以便任一部分的幀都能發送出去。這同“塞住”網絡連接同等重要。
總而言之,如果你肯定能一起發送多個數據集合(例如HTTP響應的頭和正文),那麼我們建議你設置TCP_CORK選項,這樣在這些數據之間不存在延遲。能極大地有益於WWW、FTP以及文件服務器的性能,同時也簡化了你的工作。示例代碼如下:

intfd, on = 1;

/* 此處是創建套接字等操作,出於篇幅的考慮省略*/

setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* cork */
write (fd, …);
fprintf (fd, …);
sendfile (fd, …);
write (fd, …);
sendfile (fd, …);

on = 0;
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* 拔去塞子 */

不幸的是,許多常用的程序並沒有考慮到以上問題。例如,Eric Allman編寫的sendmail就沒有對其套接字設置任何選項。

Apache HTTPD是因特網上最流行的Web服務器,它的所有套接字就都設置了TCP_NODELAY選項,而且其性能也深受大多數用戶的滿意。這是爲什麼呢?答 案就在於實現的差別之上。由BSD衍生的TCP/IP協議棧(值得注意的是FreeBSD)在這種狀況下的操作就不同。當在TCP_NODELAY 模式下提交大量小數據塊傳輸時,大量信息將按照一次write()函數調用發送一塊數據的方式發送出去。然而,因爲負責請求交付確認的記數器是面向字節而 非面向包(在Linux上)的,所以引入延遲的概率就降低了很多。結果僅僅和全部數據的大小有關係。而 Linux 在第一包到達之後就要求確認,FreeBSD則在進行如此操作之前會等待好幾百個包。

在Linux系統上,TCP_NODELAY的效果同習慣於BSD TCP/IP協議棧的開發者所期望的效果有很大不同,而且在Linux上的Apache性能表現也會更差些。其他在Linux上頻繁採用TCP_NODELAY的應用程序也有同樣的問題。

< end .entry-content >

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章