作者:
ZDNET CHINA 特稿Monday, July 22 2002 4:12 PM
當今國互聯網的飛速發展讓人們獲益匪淺,同時人們對于互聯網的期望值也變得越來越高。這就形成了一個矛盾,雖然互聯網的發展已經是相當迅猛的了,但 是人們還是期望從服務器到客戶終端的文件傳輸的速度能夠比現在再快一些,這種要求(當然是合理的要求)好像從來也滿足不了。在向人們詢問“一種什么樣的速 度對于數據傳輸來說才是最理想的”問題時,幾乎每一次你都會得到一種不同的答案:有的人認為數據傳輸的速率越快越好,有的人則認為數據傳輸的速率只要在能 夠容忍的限度之內就可以了,而另一人則認為一種數據傳輸時不會有數據損失的最快速率才是他們真正需要的,當然,這里還有許多其它的回答,我就不一一贅述 了。
在現實中,對于這個有關數據傳輸的問題是沒有一個統一的答案的。絕大多數的人在評價數據傳輸的快慢時,還是會使用“每秒鐘傳輸的兆字節數”來作為一 種衡量的標準。但是,數據傳輸快慢的真正衡量標準卻是CPU對于每一個傳輸的兆字節所花費占用的時間。對于實時應用軟件,尤其是那些傳輸視頻或者音頻數據 流的軟件,最不想出現的一種狀況就是所謂的“延遲”。CPU執行任務的時候如果沒有任何的效率,那么,要實現對協議層(protocol-level)的負載平衡(load balancing)以及將主機的IP名私人化的支持(一種叫做Virtuozzo的操作系統虛擬化技術)都是不太可能的。一個加裝了Virtuozzo的主機內能夠裝得下數以千計的網絡站點,所以,盡可能的減少用來處理數據傳輸占據的CPU時間是非常重要的。
Sendfile()是一種嶄新的操作系統核心,這種新核心能夠幫助人們解決上邊所描述的那些問題。而且,這種新內核對于UNIX, Linux, Solaris 8操作系統來說都是適用的。從技術角度來看,sendfile()是磁盤和傳輸控制協議(TCP)之間的一種系統呼叫,但是sendfile()還能夠用 來在兩個文件夾之間移動數據。在各種不同的操作系統上實現sendfile()都會有所不同,當然這種不同只是極為細微的差別。通常來說,我們會假定所使 用的操作系統是Linux核心2.4版本。
系統呼叫的原型有如下幾種:
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
- in_fd是一種用來讀文件的文件描述符。
- out_fd是一種用來寫文件的描述符。
- Offset是一種指向被輸入文件變量位置的指針,sendfile()將會從它所指向的位置開始數據的讀取。
- Count表示的是兩個文件描述符之間數據拷貝的字節數。
sendfile()的威力在于,它為大家提供了一種訪問當前不斷膨脹的Linux網絡堆棧的機制。這種機制叫做“零拷貝(zero- copy)”,這種機制可以把“傳輸控制協議(TCP)”框架直接的從主機存儲器中傳送到網卡的緩存塊(network card buffers)中去。為了更好的理解“零拷貝(zero-copy)”以及sendfile(),讓我們回憶一下以前我們在傳送文件時所需要執行的那些 步驟。首先,一塊在用戶機器存儲器內用于數據緩沖的位置先被確定了下來。然后,我們必須使用read()這條系統呼叫來把數據從文件中拷貝到前邊已經準備 好的那個緩沖區中去。(在通常的情況下,這個操做會把數據從磁盤上拷貝到操作系統的高速緩沖存儲器中去,然后才會把數據從高速緩沖存儲器中拷貝至用戶空間 中去,這種過程就是所謂的“上下文切換”。)在完成了上述的那些步驟之后,我們得使用write()系統呼叫來將緩沖區中的內容發送到網絡上去,程序段如 下所示:
intout_fd, intin_fd;
char buffer[BUFLEN];
…
/* unsubstantial code skipped for clarity */
…
read(in_fd, buffer, BUFLEN); /* syscall, make context switch */
write(out_fd, buffer, BUFLEN); /* syscall, make context switch */
操作系統核心不得不把所有的數據至少都拷貝兩次:先是從核心空間到用戶空間的拷貝,然后還得再從用戶空間拷貝回核心空間。每一次操做都需要上下文切 換(context-switch)的這個步驟,其中包含了許多復雜的高度占用CPU的操作。系統自帶的工具vmstat能夠用來在絕大多數UNIX以及 與其類似的操作系統上顯示當前的“上下文切換(context-switch)”速率。請看叫做“CS”的那一欄,有相當一部分的上下文切換是發生在取樣 期間的。用不同類型的方式進行裝載可以讓使用者清楚的看到使用這些參數進行裝載時的不同效果。
關于切換過程的一些具體細節
讓我們向著有關上下文切換過程的更深層次挖掘,這樣做能夠讓我們更好的理解有關切換的一些問題。這里有許多種有關從用戶空間呼叫系統的操作的方法。 舉個例子來說,將虛擬內存頁面從用戶空間中切換到核心,然后再切換回去的這種操作是必不可少的。這種操作過程需要的系統花銷是相當大的(尤其是在CPU周 期的占用方面)。這種操做是通過使用叫做全局描述符臺面(Global Descriptor Table)以及局部描述符臺面(Local Descriptor Table)的存儲器控制臺來實現的。另外的一種結構被稱之為TSS (Task Status Segment任務狀態段)的工具也需要大家給予足夠的重視。
此外,還有一些隱藏的非常“昂貴”的操作沒有被上下文切換程序呼叫出來。我們能夠通過虛擬內存需要虛擬物理地址翻譯操作的支持才能實現的例子來說明 這些隱藏操作的存在。這種翻譯所需要的數據也是存儲于存儲器中的,所以,CPU每一次對這些數據存儲位置的請求都需要對主存儲器進行一次或多次的訪問(這 是為了讀取翻譯臺入口),這是除了需要獲取的那些數據外還要進行的一些操作。現在的CPU通常都包含了一個翻譯緩存,其縮寫為TLB。TLB是作為頁面入 口來工作的,其中存儲了最近訪問過的對象。(這是對TLB最為簡單的解釋,其具體的解釋應為:OLE庫文件,其中存放了OLE自動化對象的數據類型、模塊 和接口定義,自動化服務器通過TLB文件就能了解自動化對象的使用方法。)TLB高速緩沖存儲器擁有巨大的潛在花費,其中包括了幾個存儲器的訪問操作以及 頁面錯誤處理器的實行操作。在拷貝大量數據的時候,會對TLB高速緩沖存儲器產生大量的消耗。在這個時候,TLB高速緩沖存儲器里邊會被要拷貝的頁面數據 占據的容不下任何別的其它數據。
在有了sendfile()零拷貝(zero-copy)之后,如果可能的話,通過使用直接存儲器訪問(Direct Memory Access)的硬件設備,數據從磁盤讀取到操作系統高速緩沖存儲器中會變得非常之迅速。而TLB高速緩沖存儲器則被完整無缺的放在那里,沒有充斥任何有 關數據傳輸的文件。應用軟件在使用sendfile() primitive的時候會有很高的性能表現,這是因為系統呼叫沒有直接的指向存儲器,因此,就提高了傳輸數據的性能。通常來說,要被傳輸的數據都是從系 統緩沖存儲器中直接讀取的,其間并沒有進行上下文切換的操作,也沒有垃圾數據占據高速緩沖存儲器。因此,在服務器應用程序中使用sendfile()能夠 顯著的減少對CPU的占用。
在我們的這個例子中取代帶有mmap() 的read()不會讓事情有什么顯著的變化。然而,mmap系統呼叫的請求是從文件中(或者從其它的一些對象中)生成一些連接信息,這些都是從在虛擬內存 中的文件描述符中指定的。試圖從虛擬內存中讀取數據會產生一些磁盤操作。因為系統會把含有映射內容的存儲器直接的寫入而不會調用read()以及緩存定 位,所以我們能夠消除磁盤讀取操作。然而,這種操作會導致TLB高速緩沖存儲器的過熱,所以CPU在裝載每個字節的傳輸時的負荷會稍微加大一些。
零拷貝的方法以及應用軟件的開發
只要有可能,在任何時候,對性能要求非??量痰目蛻舴掌鲬贸绦虻拈_發都會使用到零拷貝方法(The zero-copy approach)。設想一下,當我們需要在一個單獨的服務器上運行超過一千個分散的擁有私人IP地址的Apache網絡服務器時,就可以使用到 Virtuozzo技術了。為了達到這個目的,我們每一秒鐘都不得不在傳輸控制協議的層面上處理數以千計的請求來列出客戶的請求并且把主機名頁開列出來。 如果沒有經過最優化的處理和零拷貝(zero-copy)支持的話,這對于處理器來說將是一項繁重而且復雜的任務,甚至都超過了網絡對它的負荷。零拷貝 sendfile()的實現是基于9K-http-requests-per-second速率的,甚至在速度相對較慢的Pentium II350 MHz的處理器上也是一樣。
然而,零拷貝(zero-copy) sendfile()并不是能解決所有問題的“萬能藥”。部分的,減少網絡操作的數量,sendfile()系統呼叫應該和TCP/IP中的 TCP_CORK選項在一起共同的使用。在我們以后的文章中將會討論應用軟件從此選項中獲得的好處,以及討論其它的一些相關問題。
下面再附上兩篇文章供參考。。。
促進高效數據傳輸的TCP/IP選項
作者: ZDNET CHINA 特稿
2002-07-22 04:11 PM
在前一篇文章里,我們討論了以下問題:如何采用sendfile()系統函數降低從磁盤到網絡的數據傳輸負載。接下來我們繼續討論涉及網絡連接控制 的另一問題,同時希望通過對這一問題的討論能有助于在實際環境下把sendfile()的功能最大化,這就是如何設置TCP/IP選項來控制套接字的行 為。
TCP/IP數據傳輸
TCP/IP網絡的數據傳輸通常建立在數據塊的基礎之上。從程序員 的觀點來看,發送數據意味著發出(或者提交)一系列“發送數據塊”的請求。在系統級,發送單個數據塊可以通過調用系統函數write() 或者sendfile() 來完成。在網絡級可以看到更多的數據塊,通常把它們叫做幀,幀再被包裝上一定字節長度的報頭然后通過線路在網絡上傳輸。幀及其報頭內部的信息是由若干協議 層定義的,從OSI參考模型的物理層到應用層都可能會牽扯到。
因為在網絡連接中是由程序員來選擇最適當的應用協議,所以網絡包的長度和順序都在程序員的控制之下。同樣的,程序員還必須選擇這個協議在軟件中得以實現的方式。TCP/IP協議自身已經有了多種可互操作的實現,所以在雙方通信時,每一方都有它自身的低級行為,這也是程序員所應該知道的情況。
通常情況下,程序員不必關心操作系統和網絡協議棧發送和接收網絡數據的方法。系統內置算法定義了低級的數據組織和傳輸方式;然而,影響這些算法的行為以及對網絡連接施加更大強度控制能力的方法也是有的。例如,如果某個應用協議使用了超時和重發機制,程序員就可以采取一定措施設定或者獲取超時參數。他或她還可能需要增加發送和接收緩沖區的大小來保證網絡上的信息流動不會中斷。改變TCP/IP協議棧行為的一般的方法是采用所謂的TCP/IP選項。下面就讓我們來看一看你該如何使用這些選項來優化數據傳輸。
TCP/IP選項
有好幾種選項都能改變TCP/IP協議棧的行為。使用這些選擇能對在同一計算機上運行的其他應用程序產生不利的影響,因此普通用戶通常是不能使用這些選項的(除了root用戶以外)。我們在這里主要討論能改變單個連接操作(用TCP/IP的術語來說就是套接字)的選項。
ioctl風格的getsockopt()和setsockopt()系統函數都提供了控制套接字行為的方式。比方說,為了在Linux上設置TCP_NODELAY選項,你可以如下編寫代碼:
intfd, on = 1;
…
/* 此處是創建套接字等操作,出于篇幅的考慮省略*/
…
setsockopt (fd, SOL_TCP, TCP_NODELAY, &on, sizeof (on));
盡管有許多TCP選項可供程序員操作,而我們卻最關注如何處置其中的兩個選項,它們是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的應用程序也有同樣的問題。
相得益彰
你的數據傳輸并不需要總是準確地遵守某一選項或者其它選擇。在那種情況下,你可能想要采取更為靈活的措施來控制網絡連接:在發送一系列當作單一消息的數據之前設置TCP_CORK,而且在發送應立即發出的短消息之前設置TCP_NODELAY。
把零拷貝和sendfile() 系統函數結合起來(前文有述)可以顯著地提升系統整體效率并且降低CPU負載。我們采用這一技術為Swsoft’s Virtuozzo公司開發了基于名稱的主機托管子系統,實踐經驗表明,該技術可以在裝備350-MHz Pentium II CPU的PC上實現每秒9000個HTTP請求,這一成績在以前幾乎是不可能實現的。性能上的提高顯而易見。
利用TCP/IP選項優化數據傳輸(第2部分)
作者: BUILDER.COM
2002-07-22 04:15 PM
上回,我們對TCP_CORK選項如何減少網絡傳輸包的數量做了一番原理性的解釋。減少網絡流量當然是非常重要的優化舉措之一,不過這種手段也僅僅是實現高性能網絡數據傳輸領域的一個方面。其他TCP選項也可能顯著提供傳輸性能同時在某些條件下減少服務器的響應時間延遲。下面就讓我們來了解一些此類選項。
TCP_DEFER_ACCEPT
我們首先考慮的第1個選項是TCP_DEFER_ACCEPT(這是Linux系統上的叫法,其他一些操作系統上也有同樣的選項但使用不同的名字)。為了理解TCP_DEFER_ACCEPT選項的具體思想,我們有必要大致闡述一下典型的HTTP客戶/服務器交互過程。請回想下TCP是如何與傳輸數據的目標建立連接的。在網絡上,在分離的單元之間傳輸的信息稱為IP包(或IP 數據報)。一個包總有一個攜帶服務信息的包頭,包頭用于內部協議的處理,并且它也可以攜帶數據負載。服務信息的典型例子就是一套所謂的標志,它把包標記代表TCP/IP協議棧內的特殊含義,例如收到包的成功確認等等。通常,在經過“標記”的包里攜帶負載是完全可能的,但有時,內部邏輯迫使TCP/IP協議棧發出只有包頭的IP包。這些包經常會引發討厭的網絡延遲而且還增加了系統的負載,結果導致網絡性能在整體上降低。
現在服務器創建了一個套接字同時等待連接。TCP/IP式的連接過程就是所謂“3次握手”。首先,客戶程序發送一個設置SYN標志而且不帶數據負載 的TCP包(一個SYN包)。服務器則以發出帶SYN/ACK標志的數據包(一個SYN/ACK包)作為剛才收到包的確認響應??蛻綦S后發送一個ACK包 確認收到了第2個包從而結束連接過程。在收到客戶發來的這個SYN/ACK包之后,服務器會喚醒一個接收進程等待數據到達。當3次握手完成后,客戶程序即 開始把“有用的”的數據發送給服務器。通常,一個HTTP請求的量是很小的而且完全可以裝到一個包里。但是,在以上的情況下,至少有4個包將用來進行雙向 傳輸,這樣就增加了可觀的延遲時間。此外,你還得注意到,在“有用的”數據被發送之前,接收方已經開始在等待信息了。
為了減輕這些問題所帶來的影響,Linux(以及其他的一些操作系統)在其TCP實現中包括了TCP_DEFER_ACCEPT選項。它們設置在偵 聽套接字的服務器方,該選項命令內核不等待最后的ACK包而且在第1個真正有數據的包到達才初始化偵聽進程。在發送SYN/ACK包之后,服務器就會等待 客戶程序發送含數據的IP包?,F在,只需要在網絡上傳送3個包了,而且還顯著降低了連接建立的延遲,對HTTP通信而言尤其如此。
這一選項在好些操作系統上都有相應的對等物。例如,在FreeBSD上,同樣的行為可以用以下代碼實現:
/* 為明晰起見,此處略去無關代碼 */
struct accept_filter_arg af = { "dataready", "" };
setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));
這個特征在FreeBSD上叫做“接受過濾器”,而且具有多種用法。不過,在幾乎所有的情況下其效果與TCP_DEFER_ACCEPT是一樣的: 服務器不等待最后的ACK包而僅僅等待攜帶數據負載的包。要了解該選項及其對高性能Web服務器的重要意義的更多信息請參考Apache文檔上的有關內 容。
就HTTP客戶/服務器交互而言,有可能需要改變客戶程序的行為??蛻舫绦驗槭裁匆l送這種“無用的”ACK包呢?這是因為,TCP協議棧無法知道 ACK包的狀態。如果采用FTP而非HTTP,那么客戶程序直到接收了FTP服務器提示的數據包之后才發送數據。在這種情況下,延遲的ACK將導致客戶/ 服務器交互出現延遲。為了確定ACK是否必要,客戶程序必須知道應用程序協議及其當前狀態。這樣,修改客戶行為就成為必要了。
對Linux客戶程序來說,我們還可以采用另一個選項,它也被叫做TCP_DEFER_ACCEPT。我們知道,套接字分成兩種類型,偵聽套接字和 連接套接字,所以它們也各自具有相應的TCP選項集合。因此,經常同時采用的這兩類選項卻具有同樣的名字也是完全可能的。在連接套接字上設置該選項以后, 客戶在收到一個SYN/ACK包之后就不再發送ACK包,而是等待用戶程序的下一個發送數據請求;因此,服務器發送的包也就相應減少了。
TCP_QUICKACK
阻止因發送無用包而引發延遲的另一個方法是使用TCP_QUICKACK選項。這一選項與 TCP_DEFER_ACCEPT不同,它不但能用作管理連接建立過程而且在正常數據傳輸過程期間也可以使用。另外,它能在客戶/服務器連接的任何一方設 置。如果知道數據不久即將發送,那么推遲ACK包的發送就會派上用場,而且最好在那個攜帶數據的數據包上設置ACK 標志以便把網絡負載減到最小。當發送方肯定數據將被立即發送(多個包)時,TCP_QUICKACK選項可以設置為0。對處于“連接”狀態下的套接字該選 項的缺省值是1,首次使用以后內核將把該選項立即復位為1(這是個一次性的選項)。
在某些情形下,發出ACK包則非常有用。ACK包將確認數據塊的接收,而且,當下一塊被處理時不至于引入延遲。這種數據傳輸模式對交互過程是相當典型的,因為此類情況下用戶的輸入時刻無法預測。在Linux系統上這就是缺省的套接字行為。
在上述情況下,客戶程序在向服務器發送HTTP請求,而預先就知道請求包很短所以在連接建立之后就應該立即發送,這可謂HTTP的典型工作方式。既 然沒有必要發送一個純粹的ACK包,所以設置TCP_QUICKACK為0以提高性能是完全可能的。在服務器方,這兩種選項都只能在偵聽套接字上設置一 次。所有的套接字,也就是被接受呼叫間接創建的套接字則會繼承原有套接字的所有選項。
通過TCP_CORK、TCP_DEFER_ACCEPT和TCP_QUICKACK選項的組合,參與每一HTTP交互的數據包數量將被降低到最小 的可接受水平(根據TCP協議的要求和安全方面的考慮)。結果不僅是獲得更快的數據傳輸和請求處理速度而且還使客戶/服務器雙向延遲實現了最小化。
小結
網絡程序的性能優化顯然是一項復雜的任務。優化技術包括:盡可能使用零拷貝、用TCP_CORK及其等價選項組裝適當的數據 包、把傳輸數據包的數量最小化以及延遲優化等。為了提升網絡、系統的性能和可伸縮性,有必要在程序代碼中聯合一致地采用以上各種可用方法。當然,清楚了解 TCP/IP協議棧和操作系統的內部工作原理也是必要的。