我們先看一段網上大神的解釋 :
」tcp是乙個複雜的協議,每個機制在帶來優勢的同時也會引入其他的問題。 nagel演算法和delay ack機制是減少傳送端和接收端包量的兩個機制, 可以有效減少網路包量,避免擁塞。但是,在特定場景下, nagel演算法要求網路中只有乙個未確認的包, 而delay ack機制需要等待更多的資料報, 再傳送ack回包, 導致傳送和接收端等待對方傳送資料, 造成死鎖, 只有當delay ack超時後才能解開死鎖,進而導致應用側對外的延時高。「
我知道很多人看了這段話還是一臉懵逼,下面我來詳細通俗地解釋下。
先看nagel機制和delay ack機制
如果傳送內容大於1個mss, 立即傳送;
如果之前沒有包未被確認, 立即傳送;
如果之前有包未被確認, 快取傳送內容;
如果收到ack, 立即傳送快取的內容
如果收到的資料內容大於乙個mss, 傳送ack;
如果收到了接收視窗以為的資料, 傳送ack;
如果處於quick mode, 傳送ack;
如果收到亂序的資料, 傳送ack;
其他, 延遲傳送ack
不要慌 下面來詳細描述下這個通常延遲40ms的場景 也就是我最近遇到的
如圖所示客戶端128向服務端115傳送http請求,我把乙個請求放在兩個包裡傳送,第一次send159位元組後,服務端收到,但是159小於乙個mss同時也未收到第二個包(也就是上面視窗以為的資料或者在這裡是一次完整的http請求),所以觸發服務端delay40ms傳送ack,40ms後客戶端收到ack才開始發第二個包也就是前面http請求的下半個包。還沒理解?
沒關係,下面通俗點:
a和b商量好,a說我給你發幾個東西,發了乙個後你收到了要給我說下確保你收到了我才發下乙個,要是你一直不給我說,我這裡也不是倉庫,等我這裡的東西堆到了乙個mss那麼多,我就把這裡的所有直接打包一次發給你。
服務端b說,你一次發的東西要發完整啊,只發個腦殼的話我是不會馬上回你的,等40ms你還沒發第二個的話我再回你,要是東西實在太大你先發一半就超過了mss我也仗義回你下。
好 ,現在的情況就是a不長記性非要拆開發,先發頭,b收到頭後很生氣,這麼小你也拆散往我這裡發?老子等40ms再回你,慢慢等著。 畢竟拖太久影響業務,40ms後b回a說,頭我收到了,可以發身體了,然後這時a才開始發身體,b收到身體後由於頭和身體都完整了就馬上回a:ok,這個***娃我收到了。
解決辦法:
我今天是寫的客戶端,所以就是關閉 nagel機制,使用tcp套接字選項tcp_nodelay可以關閉套接字選項。但是通常不建議,還是乙個請求盡量只發一次好,可以使用writev,也可以把兩次寫操作的資料複製到單個緩衝區,然後對緩衝區呼叫一次write;
TCP IP之Nagle演算法與40ms延遲
nagle演算法是針對網路上存在的微小分組可能會在廣域網上造成擁塞而設計的。該演算法要求乙個tcp連線上最多只能有乙個未被確認的未完成的小分組,在該分組確認到達之前不能傳送其他的小分組。同時,tcp收集這些少量的分組,並在確認到來時以乙個分組發出去。它的設計規則如下 1 如果包長度達到最大報文長度 ...
摘抄 影響HTTP軟體的TCP時延
建立一條新的tcp連線時,甚至是在傳送任意資料之前,tcp軟體之間都會交換一系列的ip分組,對連線的有關引數進行溝通。如果連線只用來傳送少量資料,這些交換過程就會嚴重降低http的效能。通常http事務都不會交換太多資料,此時,syn syn ack握手會產生乙個可測量的時延。tcp連線的ack分組...
tcp 二次握手時延 記一次TCP效能問題
為了簡化說明這個問題,我們可以將問題抽象如下 1 有乙個http伺服器,提供乙個處理post請求的handler,這個請求裡面,可以簡化認為什麼都不做,只是讀取客戶端的request body就直接返回了。2 http客戶端傳送了乙個post請求,body大概是500kb左右。3 客戶端和伺服器處在...