歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> TCP協議缺陷不完全記錄

TCP協議缺陷不完全記錄

日期:2017/2/28 14:01:01   编辑:Linux教程

零。前言

TCP自從1974年被發明出來之後,歷經30多年發展,目前成為最重要的互聯網基礎協議。有線網絡環境下,TCP表現的如虎添翼,但在移動互聯網和物聯網環境下,稍微表現得略有不足。

移動互聯網突出特性不穩定:信號不穩定,網絡連接不穩定。雖然目前發展到4G,手機網絡帶寬有所增強,但因其流動特性,信號也不是那麼穩定:坐長途公交車,或搭乘城鐵時,或周邊上網密集時等環境,現實環境很復雜。

以下討論基於Linux服務器環境,假定環境為移動互聯網環境。記錄我目前所知TCP的一些不足,有所偏差,請給與指正。

一。三次握手

在確定傳遞數據之前需要三次握手,顯然有些多余,業界提出了TCP Fast Open (TFO)擴展機制,兩次握手之後就可以發送正常業務數據了。但這需要客戶端和服務器端內核層面都支持才行: Linux內核3.6客戶端,3.7支持服務器端。

進階閱讀:TCP Fast Open: expediting web services

二。慢啟動

一次的HTTP請求,應用層發送較大HTML頁面的數據,需要經過若干個往返循環時間(Round-Trip Time)之後,擁塞窗口才能夠擴展到最大適合數值,中間過程頗為冗余。這個參數直接關系著系統吞吐量,吞吐量大了,系統延遲小了。但設置成多大,需要根據業務進行抉擇。

3.0內核之前初始化擁塞窗口(initcwnd)大小為3。一個已建立連接初始傳輸數據時可傳遞3個MSS,若1個MSS為1400那麼一次性可傳遞4K的數據,若為10,一次性可傳遞13K的數據。

谷歌經過調研,建議移動互聯網WEB環境下建議initcwnd設置成10,linux內核3.0版本之後默認值為10。遇到較低內核,需要手動進行設置。

若是局域網環境有類似大數據或文件的傳輸需求,可以考慮適當放寬一些。

若長連接建立之後傳輸的都是小消息,每次傳輸二進制不到4K,那麼慢啟動改動與否都是無關緊要的事情了。

進階閱讀:

  • Tuning initcwnd for optimum performance
  • Optimizing Your Linux Stack for Maximum Mobile Web Performance
  • An Argument for Increasing TCP's Initial Congestion Window

三。線頭阻塞(Head-of-line blocking, HOL)

TCP協議數據傳輸需要按序傳輸,可以理解為FIFO先進先出隊列,當前面數據傳輸丟失後,後續數據單元只能等待,除非已經丟失的數據被重傳並確認接收以後,後續數據包才會被交付給客戶端設備,這就是所謂的線頭(HOL,head-of-line blocking)阻塞。比較浪費服務器帶寬又降低了系統性能,不高效。

1. 多路復用不理想

HTTP/2提出的業務層面多路復用,雖然在一定程度上解決了HTTP/1.*單路傳輸問題,但依然受制於所依賴的TCP本身線頭阻塞的缺陷。構建於TCP上層協議的多路復用,一旦發生出現線頭阻塞,需要小心對待多路的業務數據發送失敗問題。

2. TCP Keepalive機制失效

理論上TCP的Keepalive保活擴展機制,在出現線頭阻塞的時候,發送不出去被一直阻塞,完全失效。

類似於NFS文件系統,一般采用雙向的TCP Keepalive保活機制,用以規避某一端因線頭阻塞出現導致Keepalive無效的問題,及時感知一端存活情況。

3. 線頭阻塞超時提示

數據包發送了,啟動接收確認定時器,超時後會重發,重發依然無確認,後續數據會一直堆積到待發送隊列中,這裡會有一個阻塞超時,算法很復雜。上層應用會接收到來自內核協議棧的匯報"No route to host"的錯誤信息,默認不大於16分鐘時間。在服務器端(沒有業務心跳支持的情況下)發送數據前把終端強制斷線,順便結合TCPDUMP截包,等15分鐘左右內核警告"EHOSTUNREACH"錯誤,應用層面就可以看到"No route to host"的通知。

四。四次擺手

兩端連接成功建立之後,需要關閉時,需要產生四次交互,這在移動互聯網環境下,顯得有些多余。快速關閉,快速響應,冗余交互導致網絡帶寬被占用。

五。確認機制通知到上層應用?

這是一個比較美好的願望,上層應用在調用內核層接口發送大段數據,內核完成發送並且收到對方完整確認,然後通知上層應用已經發送成功,那麼在一些環境下,可以節省不少業務層面交互步驟。

六。NAT網關超時

IPV4有限,局域網環境借助於NAT路由設備擴展了接入終端設備的數量。當建立一個TCP長連接時,NAT設備需要維護一個內部終端連接外部服務器所使用的內部IP:PORT與出去的IP:PORT映射對應關系。這個關系需要維護,比較耗費內存資源,有超時定時器清理,否則會導致內存撐爆。

不同NAT設備超時值不一樣,因此才需要心跳輔助,確保經過NAT設備的連接一直保持,避免因過長的時間被踢掉。比如針對中國移動網絡連接持久時間一般設置為不超過5分鐘。各種網絡略有差異,引入智能心跳機制比較合適。

七。終端IP漫游

手機終端經常在2G/3G/4G和WIFI之間切換,導致IP地址頻繁發生改變。這樣造成的後果就是已有的網絡請求-響應被放棄和終止,需要人工干預或重新發起請求,存在資源浪費現象。

支持Multipath TCP的終端設備,可以同時利用 2G/3G/4G 和 WiFi 建立Mutlpath連接,通過多點優化網絡下載,且互為備份。可以很好解決多個網絡共存的情況下,一個網絡中斷不會導致全局請求處理中斷,在設備的連接穩定和可靠性方面有所增強。

當然,服務器之間也可以利用Multipath TCP的多個網絡增強網絡吞吐量。

現狀是:

  1. 目前只有IOS 7以及後續版本支持
  2. Linux kernel 3.10實驗分支上可以看到其支持身影,但何時合並到主分支上,暫時未知

進階閱讀:A closer look at the scientific literature on Multipath TCP

八。TCP緩存膨脹

當路由器接收到的數據包超越其隊列長度時,一般會隨機丟包,以減少膨脹。針對上層應用程序而言,延遲增加,或誤認為數據丟失,或連接丟失等。

遇到這種情況,一般建議快速發包,以避免丟失的數據部分。內核層面今早升級到最新版,不低於3.6即可。

進階閱讀:Bufferbloat

九。TCP不是絕對可靠的

  1. IP和TCP協議在頭部都會有check sum錯誤校驗和機制,16位表示,反碼相加,結果求反,具體可參考 TCP校驗和的原理和實現。一般錯誤很輕松可檢測出來,但遇到兩個16位數字相加後結果不變的情況就一籌莫展了
  2. 以太網幀CRC32校驗一般情況下都很OK,但可能遇到兩端隔離多個路由器情況下,就有可能出現問題,比如陳碩老師提供的一張圖:

    上圖中Client向Server發了一個TCP segment,這個segment先被封裝成一個IP packet,再被封裝成ethernet frame,發送到路由器(圖中消息a)。Router收到ethernet frame (b),轉發到另一個網段(c),最後Server收到d,通知應用程序。Ethernet CRC能保證a和b相同,c和d相同;TCP header check sum的強度不足以保證收發payload的內容一樣。另外,如果把Router換成NAT,那麼NAT自己會構造c(替換掉源地址),這時候a和d的payload不能用tcp header checksum校驗。

  3. 路由器可能偶然出現硬件/內存故障導致收發IP報文出現多bit/單bit的反轉或雙字節交換,這個反轉如果發生在payload區,那麼無法用鏈路層、網絡層、傳輸層的check sum查出來,只能通過應用層的check sum來檢測。因此建議應用層要設法添加校驗數據功能。

  4. 大文件下載添加校驗保證數據完整性,一般采用MD5,也用於防止安全篡改

參考資料:

  • Paper《When the CRC and TCP checksum disagree》
  • The Limitations of the Ethernet CRC and TCP/IP checksums for error detection
  • Amazon S3遇到的單bit反轉線上事故

十。小結

在這個滿世界都是TCP的環境下,要想對TCP動大手術,這個是不太可能的,因為它已經固化到已有的系統內核和固件中。比如升級終端(比如Android/IOS等)系統/固件,Linux服務器內核,中間設備/中介設備(如路由器等),這是一個浩大工程,目前看也不現實。

TCP位於系統內核層,內核空間的升級、修復,最為麻煩。服務器端升級還好說一些,用戶終端系統的升級那叫一個難。用戶空間/用戶核的應用升級、改造相對比來說可控性強,基於此Google專家們直接在UDP協議上進行構建、並且運行在用戶空間的QUIC協議,綜合了UDP的輕量和TCP的可靠性,是一個比較新穎的方向。

若是對以後底層傳輸協議有所期望的話:

  • 在用戶空間(用戶核)出現可以定制的協議,類似於QUIC
  • 傳統的TCP/UDP可以運行在用戶空間,直接略過內核
  • 完整協議棧以靜態鏈接庫形式提供給上層應用
  • 上層應用可以在編譯、打包的時包含其所依賴協議棧靜態鏈接庫so文件
  • dpdk/netmap等Packet IO框架 + 用戶空間協議堆棧,數據將從網卡直接送達上層應用
  • Linux內核重要性降低,常規的SSH系統維護

雖然TCP存在這樣、那樣的問題,但目前還是無法繞過的網絡基礎設施,但稍微明白一些不足的地方,或許會對我們當前使用的現狀有所幫助。

Copyright © Linux教程網 All Rights Reserved