24.1 引言
TCP已經在從1200 b/s的撥號SLIP鏈路到以太數據鏈路上運行了許多年。在80年代和90年代初期,以太網是運行TCP/IP最主要的數據鏈路方式。雖然TCP在比以太網速率高的環境(如T2電話線、FDDI及千兆比網絡)中也能夠正確運行,但在這些高速率環境下,TCP的某些限制就會暴露出來。
本章討論TCP的一些修改建議,這些建議可以使TCP在高速率環境中獲得最大的吞吐量。首先要討論前面已經碰到過的路徑MTU發現機制,本章主要關注它如何與TCP協同工作。這個機制通??梢允筎CP為非本地的連接使用大于536字節的MTU,從而增加吞吐量。
接著介紹長肥管道(long fat pipe),也就是那些具有很大的帶寬時延乘積的網絡,以及TCP在這些網絡上所具有的局限性。為處理長肥管道,我們描述兩個新的TCP選項:窗口擴大選項(用來增加TCP的最大窗口,使之超過65535字節)和時間戳選項。后面這個選項可以使TCP對報文段進行更加精確的RT T測量,還可以在高速率下對可能發生的序號回繞提供保護。這兩個選項在RFC 1323 [Jacobson,Braden,and Borman 1992]中進行定義。
我們還將介紹建議的T/TCP,這是為增加事務功能而對TCP進行的修改。通信的事務模式以客戶的請求將被服務器應答的響應為主要特征。這是客戶服務器計算的常見模型。T/TCP的目的就是減少兩端交換的報文段數量,避免三次握手和使用4個報文段進行連接的關閉,從而使客戶可以在一個RT T和處理請求所必需的時間內收到服務器的應答。
這些新選項(路徑MTU發現、窗口擴大選項、時間戳選項和T/TCP)中令人印象最深刻的就是它們與現有的TCP實現能夠向后兼容,即包括這些新選項的系統仍然可以與原有的舊系統進行交互。除了在一個ICMP報文中為路徑MTU發現增加了一個額外字段之外,這些新的選項只需要在那些需要使用它們的端系統中進行實現。
我們以介紹近來發表的有關TCP性能的圖例作為本章的結束。
24.2 路徑MTU發現
在2.9節我們描述了路徑MTU的概念。這是當前在兩個主機之間的路徑上任何網絡上的最小MTU。路徑MTU發現在IP首部中繼承并設置“不要分片(DF)”比特,來發現當前路徑上的路由器是否需要對正在發送的IP數據報進行分片。在11.6節我們觀察到如果一個待轉發的IP數據報被設置DF比特,而其長度又超過了MTU,那么路由器將返回ICMP不可達的差錯。在11.7節我們顯示了某版本的traceroute程序使用該機制來決定目的地的路徑MTU。在11.8節我們看到UDP是怎樣處理路徑MTU發現的。在本節我們將討論這個機制是如何按照RFC 1191 [Mogul and Deering 1990]中規定的那樣在TCP中進行使用的。
在本書的多種系統(參看序言)中只有Solaris 2.x支持路徑MTU發現。
TCP的路徑MTU發現按如下方式進行:在連接建立時,TCP使用輸出接口或對端聲明的MSS中的最小MTU作為起始的報文段大小。路徑MTU發現不允許TCP超過對端聲明的MSS。如果對端沒有指定一個MSS,則默認為536。一個實現也可以按21.9節中講的那樣為每個路由單獨保存路徑MTU信息。
一旦選定了起始的報文段大小,在該連接上的所有被TCP發送的IP數據報都將被設置DF比特。如果某個中間路由器需要對一個設置了DF標志的數據報進行分片,它就丟棄這個數據報,并產生一個我們在11.6節介紹的ICMP的“不能分片”差錯。
如果收到這個ICMP差錯,TCP就減少段大小并進行重傳。如果路由器產生的是一個較新的該類ICMP差錯,則報文段大小被設置為下一跳的MTU減去IP和TCP的首部長度。如果是一個較舊的該類ICMP差錯,則必須嘗試下一個可能的最小MTU(見圖2-5)。當由這個ICMP差錯引起的重傳發生時,擁塞窗口不需要變化,但要啟動慢啟動。
由于路由可以動態變化,因此在最后一次減少路徑MTU的一段時間以后,可以嘗試使用一個較大的值(直到等于對端聲明的MSS或輸出接口MTU的最小值)。RFC 1191推薦這個時間間隔為10分鐘(我們在11.8節看到Solaris 2.2使用一個30分鐘的時間間隔)。
在對非本地目的地,默認的MSS通常為536字節,路徑MTU發現可以避免在通過MTU小于576(這非常罕見)的中間鏈路時進行分片。對于本地目的主機,也可以避免在中間鏈路(如以太網)的MTU小于端點網絡(如令牌環網)的情況下進行分片。但為了能使路徑MTU更加有用和充分利用MTU大于576的廣域網,一個實現必須停止使用為非本地目的制定的536的MTU默認值。MSS的一個較好的選擇是輸出接口的MTU(當然要減去IP和TCP的首部大?。ㄔ诟戒汦中,我們將看到大多數的實現都允許系統管理員改變這個默認的MSS值)。
24.2.1 一個例子
在某個中間路由器的MTU比任一個端點接口MTU小的情況下,我們能夠觀察路徑MTU發現是如何工作的。圖24-1顯示了這個例子的拓撲結構。
我們從主機solaris(支持路徑MTU發現機制)到主機slip建立一個連接。這個建立過程與UDP的路徑MTU發現(圖11-13)中的一個例子相同,但在這里我們已經把slip接口的MTU設置為552,而不是通常的296。這使得slip通告一個512的MSS。但是在bsdi上的SLIP鏈路上的MTU為296,這就引起超過256的TCP報文段被分片。于是就可以觀察在solaris上的路徑MTU發現是如何進行處理的。
我們在solaris上運行sock程序并向slip上的丟棄服務器進行一個512字節的寫操作:
solaris % sock -i -n1 -w512 slip discard
圖24-2是在主機sun的SLIP接口上收集的tcpdump的輸出結果。
在第1和第2行的MSS值是我們所期望的。接著我們觀察到solaris發送一個包含512字節的數據和對SYN的確認報文段(第3行)(在習題18.9中可以看到這種把SYN的確認與第一個包含數據的報文段合并的情況)。這就在第4行產生了一個ICMP差錯,我們看到路由器bsdi產生較新的、包含輸出接口MTU的ICMP差錯。
看來在這個差錯回到solaris之前,就發送了FIN(第5行)。由于slip從沒有收到被路由器bsdi丟棄的512字節的數據,因此并不期望接收這個序號(513),所以在第6行用它期望的序號(1)進行了響應。
在這個時候,ICMP差錯返回到了solaris,solaris用兩個256字節的報文段(第7和第9行)重傳了512字節的數據。因為在bsdi后面可能還有具有更小的MTU的路由器,因此這兩個報文段都設置了DF比特。
接著是一個較長的傳輸過程(持續了大約15分鐘),在最初的512字節變為256字節以后,solaris沒有再嘗試使用更大的報文段。
24.2.2 大分組還是小分組
常規知識告訴我們較大的分組比較好 [Mogul 1993,15.2.8節],因為發送較少的大分組比發送較多的小分組“花費”要少(假定分組的大小不足以引起分片,否則會引起其他方面的問題)。這些減少的花費與網絡(分組首部負荷)、路由器(選路的決定)和主機(協議處理和設備中斷)等有關。但并非所有的人都同意這種觀點 [Bellovin 1993]。
考慮下面的例子。我們通過4個路由器發送8192個字節,每個路由器與一個T1電話線(1544 000b/s)相連。首先我們使用兩個4096字節的分組,如圖24-3所示。
基本問題在于路由器是存儲轉發設備。它們通常接收整個輸入分組,檢驗包含IP檢驗和的IP首部,進行選路判決,然后開始發送輸出分組。在這個圖中,我們可以假定在理想情況下這些在路由器內部進行的操作不花費時間(水平點狀線)。然而,從R1到R4它需要花費4個單位時間來發送所有的8192字節。每一跳的時間為
(將TCP和IP的首部算為40字節)。發送數據的整個時間為分組個數加上跳數減1,從圖中可以看到是4個單位時間,或85.6秒。每個鏈路空閑2個單位時間,或42.8秒。
圖24-4顯示了當我們發送16個512字節的分組時所發生的情況。
這將花費更多的單位時間,但是由于發送的分組較短,因此每個單位時間較小。
現在總時間為(18×2.9)=52.2 ms。每個鏈路也空閑2個單位的時間,即5.8 ms。
在這個例子中,我們忽略了確認返回所需要的時間、連接建立和終止以及鏈路可能被其他流量共享等的影響。然而,在[Bellovin 1993]中的測量表明,分組并不一定是越大越好。我們需要在更多的網絡上對該領域進行更多的研究。
24.3 長肥管道
在20.7節,我們把一個連接的容量表示為
capacity(b) = bandwidth(b/s) × round - triptime(s)
并稱之為帶寬時延乘積。也可稱它為兩端的管道大小。
當這個乘積變得越來越大時,TCP的某些局限性就會暴露出來。圖24-5顯示了多種類型的網絡的某些數值。
可以看到帶寬時延乘積的單位是字節,這是因為我們用這個單位來測量每一端的緩存大小和窗口大小。
具有大的帶寬時延乘積的網絡被稱為長肥網絡(Long Fat Network,即LFN,發音為“elefan(t)s”),而一個運行在LFN上的TCP連接被稱為長肥管道?;仡檲D20-11和圖20-12,管道可以被水平拉長(一個長的RT T),或被垂直拉高(較高的帶寬),或向兩個方向拉伸。使用長肥管道會遇到多種問題。
1:TCP首部中窗口大小為16 bit,從而將窗口限制在65535個字節內。但是從圖24-5的最后一列可以看到,現有的網絡需要一個更大的窗口來提供最大的吞吐量。在24.4節介紹的窗口擴大選項可以解決這個問題。
2:在一個長肥網絡LFN內的分組丟失會使吞吐量急劇減少。如果只有一個報文段丟失,我們需要利用21.7節介紹的快速重傳和快速恢復算法來使管道避免耗盡。但是即使使用這些算法,在一個窗口內發生的多個分組丟失也會典型地使管道耗盡(如果管道耗盡了,慢啟動會使它漸漸填滿,但這個過程將需要經過多個RTT)。
在RFC 1072 [Jacobson and Braden 1988]中建議使用有選擇的確認(SACK)來處理在一個窗口發生的多個分組丟失。但是這個功能在RFC 1323中被忽略了,因為作者覺得在把它們納入TCP之前需要先解決一些技術上的問題。
3:我們在第21.4節看到許多TCP實現對每個窗口的RTT僅進行一次測量。它們并不對每個報文段進行RTT測量。在一個長肥網絡LFN上需要更好的RTT測量機制。我們將在24.5節介紹時間戳選項,它允許更多的報文段被計時,包括重傳。
4:TCP對每個字節數據使用一個32 bit無符號的序號來進行標識。如果在網絡中有一個被延遲一段時間的報文段,它所在的連接已被釋放,而一個新的連接在這兩個主機之間又建立了,怎樣才能防止這樣的報文段再次出現呢?首先回想起IP首部中的TTL為每個IP段規定了一個生存時間的上限—255跳或255秒,看哪一個上限先達到。在18.6節我們定義了最大的報文段生存時間(MSL)作為一個實現的參數來阻止這種情況的發生。推薦的MSL的值為2分鐘(給出一個240秒的2MSL),但是我們在18.6節看到許多實現使用的MSL為30秒。
在長肥網絡LFN上,TCP的序號會碰到一個不同的問題。由于序號空間是有限的,在已經傳輸了4294 967 296個字節以后序號會被重用。如果一個包含序號N字節數據的報文段在網絡上被遲延并在連接仍然有效時又出現,會發生什么情況呢?這僅僅是一個相同序號N在MSL期間是否被重用的問題,也就是說,網絡是否足夠快以至于在不到一個MSL的時候序號就發生了回繞。在一個以太網上要發送如此多的數據通常需要60分鐘左右,因此不會發生這種情況。但是在帶寬增加時,這個時間將會減少:一個T3的電話線(45 Mb/s)在12分鐘內會發生回繞,FDDI(100 Mb/s)為5分鐘,而一個千兆比網絡(1000 Mb/s)則為34秒。這時問題不再是帶寬時延乘積,而在于帶寬本身。
在24.6節,我們將介紹一種對付這種情況的辦法:使用TCP的時間戳選項的PAW S(Protection Against Wrapped Sequence numbers)算法(保護回繞的序號)。
4.4BSD包含了我們將要在下面介紹的所有選項和算法:窗口擴大選項、時間戳選項和保護回繞的序號。許多供應商也正在開始支持這些選項
千兆比網絡
當網絡的速率達到千兆比的時候,情況就會發生變化。[Partridge 1994]詳細介紹了千兆比網絡。在這里我們看一下在時延和帶寬之間的差別 [Kleinrock 1992]。
考慮通過美國發送一個100萬字節的文件的情況,假定時延為30 ms。圖24-6顯示了兩種情況:上圖顯示了使用一個T1電話線(1544 000 b/s)的情況,而下圖則是使用一個1Gb/s網絡的情況。x軸顯示的是時間,發送方在圖的左側,而接收方則在圖的右側,y軸為網絡容量。兩幅圖中的陰影區域表示發送的100萬字節。
圖24-6顯示了30 ms后這兩個網絡的狀態。經過30 ms(延時)以后數據的第1個比特都已到達對端。但對T1網絡而言,由于管道容量僅為5790字節,因此發送方仍然有994 210個字節等待發送。而千兆比網絡的容量則為3750 000字節,因此,整個文件僅使用了25%左右的帶寬,此時文件的最后一個比特已經到達第1個字節后8ms處。
經過T1網絡傳輸文件的總時間為5.211秒。如果增加更多的帶寬,使用一個T3網絡(45 000 000 b/s),則總時間減少到0.208秒。增加約29倍的帶寬可以將總時間減小到約25分之一。
使用千兆比網絡傳輸文件的總時間為0.038秒:30 ms的時延加上8ms的真正傳輸文件的時間。假定能夠將帶寬增加為2000 Mb/s,我們只能夠將總時間減小為0.304 ms:同樣30 ms的時延和4ms的真正傳輸時間?,F在使帶寬加倍僅能夠將時間減少約10%。在千兆比速率下,時延限制占據了主要地位,而帶寬不再成為限制。
時延主要是由光速引起的,而且不能夠被減小(除非愛因斯坦是錯誤的)。當我們考慮到分組需要建立和終止一個連接時,這個固定時延起的作用就更糟糕了。千兆比網絡會引起一些需要不同看待的連網觀點。
24.4 窗口擴大選項
窗口擴大選項使TCP的窗口定義從16 bit增加為32 bit。這并不是通過修改TCP首部來實現的,TCP首部仍然使用16 bit,而是通過定義一個選項實現對16 bit的擴大操作(scaling operation)來完成的。于是TCP在內部將實際的窗口大小維持為32 bit的值。
在圖18-20可以看到關于這個選項的例子。一個字節的移位記數器取值為0(沒有擴大窗口的操作)和14。這個最大值14表示窗口大小為1073 725 440字節(65535×214)。
這個選項只能夠出現在一個SYN報文段中,因此當連接建立起來后,在每個方向的擴大因子是固定的。為了使用窗口擴大,兩端必須在它們的SYN報文段中發送這個選項。主動建立連接的一方在其SYN中發送這個選項,但是被動建立連接的一方只能夠在收到帶有這個選項的SYN之后才可以發送這個選項。每個方向上的擴大因子可以不同。
如果主動連接的一方發送一個非零的擴大因子,但是沒有從另一端收到一個窗口擴大選項,它就將發送和接收的移位記數器置為0。這就允許較新的系統能夠與較舊的、不理解新選項的系統進行互操作。
Host Requirements RFC要求TCP接受在任何報文段中的一個選項(只有前面定義的一個選項,即最大報文段大小,僅在SYN報文段中出現)。它還進一步要求TCP忽略任何它不理解的選項。這就使事情變得容易,因為所有新的選項都有一個長度字段(圖18-20)。
假定我們正在使用窗口擴大選項,發送移位記數為S,而接收移位記數則為R。于是我們從另一端收到的每一個16 bit的通告窗口將被左移R位以獲得實際的通告窗口大小。每次當我們向對方發送一個窗口通告的時候,我們將實際的32 bit窗口大小右移S比特,然后用它來替換TCP首部中的16 bit的值。
TCP根據接收緩存的大小自動選擇移位計數。這個大小是由系統設置的,但是通常向應用進程提供了修改途徑(我們在20.4節中討論了這個緩存)。
一個例子
如果在4.4BSD的主機vangogh.cs.berkeley.edu上使用sock程序來初始化一個連接,我們可以觀察到它的TCP計算窗口擴大因子的情況。下面的交互輸出顯示的是兩個連續運行的程序,第1個指定接收緩存為128 000字節,而第2個的緩存則為220 000字節。
在第1行,vangogh通告一個65535的窗口,并通過設置移位計數為1來指明窗口擴大選項。這個通告的窗口是比接收窗口(128 000)還小的一個最大可能取值,因為在一個SYN報文段中的窗口字段從不進行擴大運算。
擴大因子為1表示vangogh發送窗口通告一直到131 070(65535×21)。這將調節我們的接收緩存的大?。?2 8000)。因為bsdi在它的SYN(第2行)中沒有發送窗口擴大選項,因此這個選項沒有被使用。注意到vangogh在隨后的連接階段繼續使用最大可能的窗口(65535)。
對于第2個連接vangogh請求的移位計數為2,表明它希望發送窗口通告一直為262 140(65535×22),這比我們的接收緩存(220 000)大。
24.5 時間戳選項
時間戳選項使發送方在每個報文段中放置一個時間戳值。接收方在確認中返回這個數值,從而允許發送方為每一個收到的ACK計算RTT(我們必須說“每一個收到的ACK”而不是“每一個報文段”,是因為TCP通常用一個ACK來確認多個報文段)。我們提到過目前許多實現為每一個窗口只計算一個RTT,對于包含8個報文段的窗口而言這是正確的。然而,較大的窗口大小則需要進行更好的RTT計算。
RFC 1323的3.1節給出了需要為較大窗口進行更好的RTT計算的信號處理的理由。通常RTT通過對一個數據信號(包含數據的報文段)以較低的頻率(每個窗口一次)進行采樣來進行計算,這就將別名引入了被估計的RTT中。當每個窗口中有8個報文段時,采樣速率為數據率的1/8,這還是可以忍受的。但是如果每個窗口中有100個報文段時,采樣速率則為數據速率的1/100,這將導致被估計的RTT不精確,從而引起不必要的重傳。如果一個報文段被丟失,則會使情況變得更糟。
圖18-20顯示了時間戳選項的格式。發送方在第1個字段中放置一個32 bit的值,接收方在應答字段中回顯這個數值。包含這個選項的TCP首部長度將從正常的20字節增加為32字節。
時間戳是一個單調遞增的值。由于接收方只需要回顯收到的內容,因此不需要關注時間戳單元是什么。這個選項不需要在兩個主機之間進行任何形式的時鐘同步。RFC 1323推薦在1毫秒和1秒之間將時間戳的值加1。
4.4BSD在啟動時將時間戳始終設置為0,然后每隔500 ms將時間戳時鐘加1。
在圖24-7中,如果觀察在報文段1和報文段11的時間戳,它們之間的差(89個單元)對應于每個單元500 ms的規定,因為實際時間差為44.4秒。
在連接建立階段,對這個選項的規定與前一節講的窗口擴大選項類似。主動發起連接的一方在它的SYN中指定選項。只有在它從另一方的SYN中收到了這個選項之后,該選項才會在以后的報文段中進行設置。
我們已經看到接收方TCP不需要對每個包含數據的報文段進行確認,許多實現每兩個報文段發送一個ACK。如果接收方發送一個確認了兩個報文段的ACK,那么哪一個收到的時間戳應當放入回顯應答字段中來發回去呢?
為了減少任一端所維持的狀態數量,對于每個連接只保持一個時間戳的數值。選擇何時更新這個數值的算法非常簡單:
1:TCP跟蹤下一個ACK中將要發送的時間戳的值(一個名為tsrecent的變量)以及最后發送的ACK中的確認序號(一個名為lastack的變量)。這個序號就是接收方期望的序號。
2:當一個包含有字節號lastack的報文段到達時,則該報文段中的時間戳被保存在tsrecent中。
3:無論何時發送一個時間戳選項,tsrecent就作為時間戳回顯應答字段被發送,而序號字段被保存在lastack中。
這個算法能夠處理下面兩種情況:
1:如果ACK被接收方遲延,則作為回顯值的時間戳值應該對應于最早被確認的報文段。例如,如果兩個包含11024和10252048字節的報文段到達,每一個都帶有一個時間戳選項,接收方產生一個ACK 2049來對它們進行確認。此時,ACK中的時間戳應該是包含字節1~1024的第1個報文段中的時間戳。這種處理是正確的,因為發送方在進行重傳超時時間的計算時,必須將遲延的ACK也考慮在內。
2:如果一個收到的報文段雖然在窗口范圍內但同時又是失序,這就表明前面的報文段已經丟失。當那個丟失的報文段到達時,它的時間戳(而不是失序的報文段的時間戳)將被回顯。例如,假定有3個各包含1024字節數據的報文段,按如下順序接收:包含字節11024的報文段1,包含字節20494072的報文段3和包含字節1025~2048的報文段2。返回的ACK應該是帶有報文段1的時間戳的ACK 1025(一個正常的所期望的對數據的ACK)、帶有報文段1的時間戳的ACK 1025(一個重復的、響應位于窗口內但卻是失序的報文段的ACK),然后是帶有報文段2的時間戳的ACK 3073(不是報文段3中的較后的時間戳)。這與當報文段丟失時的對RT T估計過高具有同樣的效果,但這比估計過低要好些。而且,如果最后的ACK含有來自報文段3的時間戳,它可以包括重復的ACK返回和報文段2被重傳所需要的時間,或者可以包括發送方的報文段2的重傳超時定時器到期的時間。無論在哪一種情況下,回顯報文段3的時間戳將引起發送方的RT T計算出現偏差。
盡管時間戳選項能夠更好地計算RTT,它還為發送方提供了一種方法,以避免接收到舊的報文段,并認為它們是現在的數據的一部分。下一節將對此進行描述。
24.6 PAWS:防止回繞的序號
考慮一個使用窗口擴大選項的TCP連接,其最大可能的窗口大小為1千兆字節(230)(最大的窗口是65535×214,而不是216×214,但只比這個數值小一點點,并不影響這里的討論)。還假定使用了時間戳選項,并且由發送方指定的時間戳對每個將要發送的窗口加1(這是保守的方法。通常時間戳比這種方式增加得快)。圖24-8顯示了在傳輸6千兆字節的數據時,在兩個主機之間可能的數據流。為了避免使用許多10位的數字,我們使用G來表示1073 741 824的倍數。我們還使用了tcpdump的記號,即用J:K來表示通過了J字節的數據,且包括字節K-1。
32 bit的序號在時間D和時間E之間發生了回繞。假定一個報文段在時間B丟失并被重傳。還假定這個丟失的報文段在時間E重新出現。
這假定了在報文段丟失和重新出現之間的時間差小于MSL,否則這個報文段在它的TTL到期時會被某個路由器丟棄。正如我們前面提到的,這種情況只有在高速連接上才會發生,此時舊的報文段重新出現,并帶有當前要傳輸的序號。
我們還可以從圖24-8中觀察到使用時間戳可以避免這種情況。接收方將時間戳視為序列號的一個32 bit的擴展。由于在時間E重新出現的報文段的時間戳為2,這比最近有效的時間戳小(5或6),因此PAWS算法將其丟棄。
PAWS算法不需要在發送方和接收方之間進行任何形式的時間同步。接收方所需要的就是時間戳的值應該單調遞增,并且每個窗口至少增加1。
24.7 T/TCP:為事務用的TCP擴展
TCP提供的是一種虛電路方式的運輸服務。一個連接的生存時間包括三個不同的階段:建立、數據傳輸和終止。這種虛電路服務非常適合諸如遠程注冊和文件傳輸之類的應用。
但是,還有出現其他的應用進程被設計成使用事務服務。一個事務(transaction)就是符合下面這些特征的一個客戶請求及其隨后的服務器響應。
1:應該避免連接建立和連接終止的開銷,在可能的時候,發送一個請求分組并接收一個應答分組。
2:等待時間應當減少到等于RTT與SPT之和。其中RTT(Round-Trip Time)為往返時間,而SPT(Server Processing Time)則是服務器處理請求的時間。
3:服務器應當能夠檢測出重復的請求,并且當收到一個重復的請求時不重新處理事務(避免重新處理意味著服務器不必再次處理請求,而是返回保存的、與該請求對應的應答)。
我們已經看到的一個使用這種類型服務的應用就是域名服務(第14章),盡管DNS與服務器重新處理重復的請求無關。
如今一個應用程序設計人員面對的一種選擇是使用TCP還是UDP。TCP提供了過多的事務特征,而UDP提供的則不夠。通常應用程序使用UDP來構造(避免TCP連接的開銷),而許多需要的特征(如動態超時和重傳、擁塞避免等)被放置在應用層,一遍又一遍的重新設計和實現。
一個較好的解決方法是提供一個能夠提供足夠多的事務處理功能的運輸層。我們在本節所介紹的事務協議被稱為T/TCP。我們從它的定義,即RFC 1379 [Braden 1992b]和[Braden1992c],開始介紹。
大多數的TCP需要使用7個報文段來打開和關閉一個連接(見圖18-13)。現在增加三個報文段:一個對應于請求,一個對應于應答和對請求的確認,第三個對應于對應答的確認。如果額外的控制比特被追加到報文段上—也就是,第1個報文段帶有SYN、客戶請求和一個FIN—客戶仍然能夠看到一個2倍的RTT與SPT之和的最小開銷(與數據一起發送一個SYN和FIN是合法的;當前的TCP是否能夠正確處理它們是另外一個問題)。
另一個與TCP有關的問題是TIME_WAIT狀態和它需要的2MSL的等待時間。正如在習題18.14中看到的,這使兩個主機之間的事務率降低到每秒268個。
TCP為處理事務而需要進行的兩個改動是避免三次握手和縮短WAIT_TIME狀態。T/TCP通過使用加速打開來避免三次握手:
1:它為打開的連接指定一個32 bit的連接計數CC(Connection Count),無論主動打開還是被動打開。一個主機的CC值從一個全局計數器中獲得,該計數器每次被使用時加1。
2:在兩個使用T/TCP的主機之間的每一個報文段都包括一個新的TCP選項CC。這個選項的長度為6個字節,包含發送方在該連接上的32 bit的CC值。
3:一個主機維持一個緩存,該緩存保留每個主機上一次的CC值,這些值從來自這個主機的一個可接受的SYN報文段中獲得。
4:當在一個開始的SYN中收到一個CC選項的時候,接收方比較收到的值與為該發送方緩存的CC值。如果接收到的CC比緩存的大,則該SYN是新的,報文段中的任何數據被傳遞給接收應用進程(服務器)。這個連接被稱為半同步。如果接收的CC比緩存的小,或者接收主機上沒有對應這個客戶的緩存CC,則執行正常的TCP三次握手過程。
5:為響應一個開始的SYN,帶有SYN和ACK的報文段在另一個被稱為CCECHO的選項中回顯所接收到的CC值。
6:在一個非SYN報文段中的CC值檢測和拒絕來自同一個連接的前一個替身的任何重復的報文段。
這種“加速打開”避免了使用三次握手的要求,除非客戶或者服務器已經崩潰并重新啟動。這樣做的代價是服務器必須記住從每個客戶接收的最近的CC值。
基于在兩個主機之間測量RTT來動態計算TIME_WAIT的延時,可以縮短TIME_WAIT狀態。TIME_WAIT時延被設置為8倍的重傳超時值RTO(見21.3節)。
通過使用這些特征,最小的事務序列是交換三個報文段:
1:由一個主動打開引起的客戶到服務器:客戶的SYN、客戶的數據(請求)、客戶的FIN以及客戶的CC。當被動的服務器TCP接收到這個報文段的時候,如果客戶的CC比為這個客戶緩存的CC要大,則客戶的數據被傳送給服務器應用程序進行處理。
2:服務器到客戶:服務器的SYN、服務器的數據(應答)、服務器的FIN、對客戶的FIN的ACK、服務器的CC以及客戶的CC的CCECHO。由于TCP的確認是累積的,這個對客戶的FIN的ACK也對客戶的SYN、數據及FIN進行了確認。
當客戶TCP接收到這個報文段,就將其傳送給客戶應用進程。
3:客戶到服務器:對服務器的FIN的ACK,它也確認了服務器的SYN、數據和FIN??蛻魧λ恼埱蟮捻憫獣r間為RTT與SPT的和。
在參考資料中有許多關于實現這個TCP選項的很好的地方。我們在這里將它們歸納如下:
1:服務器的SYN和ACK(第2個報文段)必須被遲延,從而允許應答與它一起捎帶發送(通常對SYN的ACK是不遲延的)。但它也不能遲延得太多,否則客戶將超時并引起重傳。
2:請求可以需要多個報文段,但是服務器必須對它們可能失序達到的情況進行處理(通常當數據在SYN之前到達時,該數據被丟棄并產生一個復位。通過使用T/TCP,這些失序的數據將放入隊列中處理)。
3:API必須使服務器進程用一個單一的操作來發送數據和關閉連接,從而允許第二個報文段中的FIN與應答一起捎帶發送(通常應用進程先寫應答,從而引起發送一個數據報文段,然后關閉連接,引起發送FIN)。
4:在收到來自服務器的MSS通告之前,客戶在第1個報文段中正在發送數據。為避免限制客戶的MSS為536,一個給定主機的MSS應該與它的CC值一起緩存。
5:客戶在沒有接收到來自服務器的窗口通告之前也可以向服務器發送數據。T/TCP建議默認的窗口為4096,并且也為服務器緩存擁塞門限。
6:使用最小3個報文段交換,在每個方向上只能計算一個RTT。加上包括了服務器處理時間的客戶測量RT T。這意味著被平滑的RTT及其方差的值也必須為服務器緩存起來,這與我們在21.9節描述的類似。
T/TCP的特征中吸引人的地方在于它對現有協議進行了最小的修改,同時又兼容了現有的實現。它還利用了TCP中現有的工程特征(動態超時和重傳、擁塞避免等),而不是迫使應用進程來處理這些問題。
一個可作為替換的事務協議是通用報文事務協議VMTP(Versatile Message Transaction Protocol),該協議在RFC 1045 [Cheriton 1988]中進行了描述。與T/TCP是現有協議的一個小的擴充不同,VMTP是使用IP的一個完整的運輸層。VMTP處理差錯檢測、重傳和重復壓縮。它還支持多播通信。
24.8 TCP的性能
在80年代中期出版的數值顯示出TCP在一個以太網上的吞吐量在每秒100 000~200 000字節之間([Stevens 1990]的17.5節給出了參考文獻)。從那時起事情已經發生了許多改變?,F在通常使用的硬件(工作站和更快的個人電腦)每秒可以傳輸800 000字節或者更快。
在10Mb/s的以太網上計算我們能夠觀察到的理論上的TCP最大吞吐量是一件值得做的練習[Warnock 1991]。我們可以在圖24-9中看到這個計算的基礎。這個圖顯示了滿長度的數據報文段和一個ACK交換的全部的字節。
我們必須計及所有的開銷:前同步碼、加到確認上的填充字節、循環冗余檢驗CRC以及分組之間的最小間隔(9.6ms,相當在10 Mb/s速率下的12個字節)。
首先假定發送方傳輸兩個背對背、滿長度的數據報文段,然后接收方為這兩個報文段發送一個ACK。于是最大的吞吐量(用戶數據)為:
如果TCP窗口開到它的最大值(65535,不使用窗口擴大選項),這就允許一個窗口容納44個1460字節的報文段。如果接收方每個報文段發送一個ACK,則計算變為:
這就是理論上的限制,并做出某些假定:接收方發送的一個ACK沒有和發送方的報文段之一在以太網上發生沖突;發送方可按以太網的最小間隔時間來發送兩個報文段;接收方可以在最小的以太網間隔時間內產生一個ACK。不論在這些數字上多么樂觀,[Warnock 1991]在一個以太網上使用標準的多用戶工作站(即使是快的工作站)測量到了一個連續的1075 000字節/秒的速率,這個值在理論值的90%之內。
當移到更快的網絡上時,如FDDI(100 Mb/s),[Schryver 1993]指出三個商業廠家已經演示了在FDDI上的TCP在80 Mb/s~90 Mb/s之間。即使在有更多帶寬的環境下,[Borman 1992]報告說兩個Gray Y-MP計算機在一個800 Mb/s的HIPPI通道上最大值為781 Mb/s,而運行在一個Gray Y-MP上的使用環回接口的兩個進程間的速率為907 Mb/s。
下面這些實際限制適用于任何的實際情況[Borman 1991]。
1:不能比最慢的鏈路運行得更快。
2:不能比最慢的機器的內存運行得更快。這假定實現是只使用一遍數據。如果不是這樣(也就是說,實現使用一遍數據是將它從用戶空間復制到內核中,而使用另一遍數據是計算TCP的檢驗和),那么將運行得更慢。[Dalton et al.1993]描述了將數據復制數目減少從而使一個標準伯克利源程序的性能得到改進。[Partridge and Pink 1993]將類似的“復制與檢驗和”的改變與其他性能改進措施一道應用于UDP,從而將UDP的性能提高了約30%。
3:不能夠比由接收方提供的窗口大小除以往返時間所得結果運行得更快(這就是帶寬時延乘積公式,使用窗口大小作為帶寬時延乘積,并解出帶寬)。如果使用24.4節的最大窗口擴大因子14,則窗口大小為1.073千兆字節,所以這除以RTT的結果就是帶寬的極限。
所有這些數字的重要意義就是TCP的最高運行速率的真正上限是由TCP的窗口大小和光速決定的。正如[Partridge and Pink 1993]中計算的那樣,許多協議性能問題在于實現中的缺陷而不是協議所固有的一些限制。
24.9 小結
本章已經討論了五個新的TCP特征:路徑MTU發現、窗口擴大選項、時間戳選項、序號回繞保護以及使用改進的TCP事務處理。我們觀察到中間的三個特征是為在長肥管道——具有大的帶寬時延乘積的網絡—上優化性能所需要的。
路徑MTU發現在MTU較大時,對于非本地連接,允許TCP使用比默認的536大的窗口。這樣可以提高性能。
窗口擴大選項使最大的TCP窗口從65535增加到1千兆字節以上。時間戳選項允許多個報文段被精確計時,并允許接收方提供序號回繞保護(PAWS)。這對于高速連接是必須的。這些新的TCP選項在連接時進行協商,并被不理解它們的舊系統忽略,從而允許較新的系統與舊的系統進行交互。
為事務用的TCP擴展,即T/TCP,允許一個客戶/服務器的請求-應答序列在通常的情況下只使用三個報文段來完成。它避免使用三次握手,并縮短了TIME_WAIT狀態,其方法是為每個主機高速緩存少量的信息,這些信息曾用來建立過一個連接。它還在包含數據報文段中使用SYN和FIN標志。
由于還有許多關于TCP能夠運行多快的不精確的傳聞,因此我們以對TCP性能的分析來結束本章。對于一個使用本章介紹的較新特征、協調得非常好的實現而言,TCP的性能僅受最大的1千兆字節窗口和光速(也就是往返時間)的限制。