聶永的博客

          記錄工作/學(xué)習(xí)的點點滴滴。

          TCP協(xié)議缺陷不完全記錄

          零。前言

          TCP自從1974年被發(fā)明出來之后,歷經(jīng)30多年發(fā)展,目前成為最重要的互聯(lián)網(wǎng)基礎(chǔ)協(xié)議。有線網(wǎng)絡(luò)環(huán)境下,TCP表現(xiàn)的如虎添翼,但在移動互聯(lián)網(wǎng)和物聯(lián)網(wǎng)環(huán)境下,稍微表現(xiàn)得略有不足。

          移動互聯(lián)網(wǎng)突出特性不穩(wěn)定:信號不穩(wěn)定,網(wǎng)絡(luò)連接不穩(wěn)定。雖然目前發(fā)展到4G,手機網(wǎng)絡(luò)帶寬有所增強,但因其流動特性,信號也不是那么穩(wěn)定:坐長途公交車,或搭乘城鐵時,或周邊上網(wǎng)密集時等環(huán)境,現(xiàn)實環(huán)境很復(fù)雜。

          以下討論基于Linux服務(wù)器環(huán)境,假定環(huán)境為移動互聯(lián)網(wǎng)環(huán)境。記錄我目前所知TCP的一些不足,有所偏差,請給與指正。

          一。三次握手

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

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

          二。慢啟動

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

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

          谷歌經(jīng)過調(diào)研,建議移動互聯(lián)網(wǎng)WEB環(huán)境下建議initcwnd設(shè)置成10,linux內(nèi)核3.0版本之后默認(rèn)值為10。遇到較低內(nèi)核,需要手動進行設(shè)置。

          若是局域網(wǎng)環(huán)境有類似大數(shù)據(jù)或文件的傳輸需求,可以考慮適當(dāng)放寬一些。

          若長連接建立之后傳輸?shù)亩际切∠ⅲ看蝹鬏敹M制不到4K,那么慢啟動改動與否都是無關(guān)緊要的事情了。

          進階閱讀:

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

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

          1. 多路復(fù)用不理想

          HTTP/2提出的業(yè)務(wù)層面多路復(fù)用,雖然在一定程度上解決了HTTP/1.*單路傳輸問題,但依然受制于所依賴的TCP本身線頭阻塞的缺陷。構(gòu)建于TCP上層協(xié)議的多路復(fù)用,一旦發(fā)生出現(xiàn)線頭阻塞,需要小心對待多路的業(yè)務(wù)數(shù)據(jù)發(fā)送失敗問題。

          2. TCP Keepalive機制失效

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

          類似于NFS文件系統(tǒng),一般采用雙向的TCP Keepalive保活機制,用以規(guī)避某一端因線頭阻塞出現(xiàn)導(dǎo)致Keepalive無效的問題,及時感知一端存活情況。

          3. 線頭阻塞超時提示

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

          四。四次擺手

          兩端連接成功建立之后,需要關(guān)閉時,需要產(chǎn)生四次交互,這在移動互聯(lián)網(wǎng)環(huán)境下,顯得有些多余。快速關(guān)閉,快速響應(yīng),冗余交互導(dǎo)致網(wǎng)絡(luò)帶寬被占用。

          五。確認(rèn)機制通知到上層應(yīng)用?

          這是一個比較美好的愿望,上層應(yīng)用在調(diào)用內(nèi)核層接口發(fā)送大段數(shù)據(jù),內(nèi)核完成發(fā)送并且收到對方完整確認(rèn),然后通知上層應(yīng)用已經(jīng)發(fā)送成功,那么在一些環(huán)境下,可以節(jié)省不少業(yè)務(wù)層面交互步驟。

          六。NAT網(wǎng)關(guān)超時

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

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

          七。終端IP漫游

          手機終端經(jīng)常在2G/3G/4G和WIFI之間切換,導(dǎo)致IP地址頻繁發(fā)生改變。這樣造成的后果就是已有的網(wǎng)絡(luò)請求-響應(yīng)被放棄和終止,需要人工干預(yù)或重新發(fā)起請求,存在資源浪費現(xiàn)象。

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

          當(dāng)然,服務(wù)器之間也可以利用Multipath TCP的多個網(wǎng)絡(luò)增強網(wǎng)絡(luò)吞吐量。

          現(xiàn)狀是:

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

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

          八。TCP緩存膨脹

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

          遇到這種情況,一般建議快速發(fā)包,以避免丟失的數(shù)據(jù)部分。內(nèi)核層面今早升級到最新版,不低于3.6即可。

          進階閱讀:Bufferbloat

          九。TCP不是絕對可靠的

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

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

          3. 路由器可能偶然出現(xiàn)硬件/內(nèi)存故障導(dǎo)致收發(fā)IP報文出現(xiàn)多bit/單bit的反轉(zhuǎn)或雙字節(jié)交換,這個反轉(zhuǎn)如果發(fā)生在payload區(qū),那么無法用鏈路層、網(wǎng)絡(luò)層、傳輸層的check sum查出來,只能通過應(yīng)用層的check sum來檢測。因此建議應(yīng)用層要設(shè)法添加校驗數(shù)據(jù)功能。

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

          參考資料:

          十。小結(jié)

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

          TCP位于系統(tǒng)內(nèi)核層,內(nèi)核空間的升級、修復(fù),最為麻煩。服務(wù)器端升級還好說一些,用戶終端系統(tǒng)的升級那叫一個難。用戶空間/用戶核的應(yīng)用升級、改造相對比來說可控性強,基于此Google專家們直接在UDP協(xié)議上進行構(gòu)建、并且運行在用戶空間的QUIC協(xié)議,綜合了UDP的輕量和TCP的可靠性,是一個比較新穎的方向。

          若是對以后底層傳輸協(xié)議有所期望的話:

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

          雖然TCP存在這樣、那樣的問題,但目前還是無法繞過的網(wǎng)絡(luò)基礎(chǔ)設(shè)施,但稍微明白一些不足的地方,或許會對我們當(dāng)前使用的現(xiàn)狀有所幫助。

          posted on 2015-05-07 14:56 nieyong 閱讀(15609) 評論(3)  編輯  收藏

          評論

          # re: TCP協(xié)議缺陷不完全記錄 2015-05-29 13:26 中國設(shè)計星

          嗯,這個很實用,先收藏了。  回復(fù)  更多評論   

          # re: TCP協(xié)議缺陷不完全記錄 2015-11-05 14:11 ikillmeba

          學(xué)習(xí)學(xué)習(xí)  回復(fù)  更多評論   

          # re: TCP協(xié)議缺陷不完全記錄 2016-05-07 15:06 redsmith

          非常好,贊!  回復(fù)  更多評論   


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2015年5月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          統(tǒng)計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 会昌县| 华安县| 临汾市| 广元市| 乌恰县| 红安县| 正蓝旗| 汉阴县| 金溪县| 金乡县| 伊吾县| 望奎县| 阜新市| 光泽县| 海宁市| 前郭尔| 隆德县| 同仁县| 镇安县| 保康县| 平果县| 河源市| 蚌埠市| 吴旗县| 从化市| 东至县| 延长县| 邵武市| 图片| 宁阳县| 庄浪县| 乐陵市| 特克斯县| 即墨市| 贡嘎县| 山丹县| 大庆市| 济源市| 定南县| 潜江市| 衡东县|