TCP 重傳問題排查思路與實踐
圖 under the strange horizon by joeyjazz
一 關於TCP重傳
-
TCP 有重傳是正常的機制,為了保障資料傳輸可靠性。只是區域網環境,網路質量有保障,因為網路問題出現重傳應該極低;網際網路或都會網路環境,線路複雜(可以想象下城市地下管網,錯綜複雜的電線杆等),網路質量不好保障,重傳出現概率較高。
-
TCP 有重傳,也不一定是網路層面的問題。也可能是接收端不存在,接收端receive buffer滿了,應用程式有異常連結未正常關閉等等等。
二 TCP/IP相關
排查網路問題,要掌握TCP/IP原理,真相都在一個一個的資料包裡。以下是和 TCP 重傳比較關鍵的幾個引數。
2.1 建立 TCP 連結時的引數
net.ipv4.tcp_syn_retries#syn包重傳多少次後放棄,重傳間隔是2的n次方(1s,2s,4s..) net.ipv4.tcp_synack_retries#syn ack包重傳多少次後放棄 net.ipv4.tcp_max_syn_backlog#syn包佇列
其他參考:
/proc/sys/net/ipv4/* Variables: https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
2.2 TCP重傳型別
超時重傳
在請求包發出去的時候,開啟一個計時器,當計時器達到時間之後,沒有收到ACK,則就進行重發請求的操作,一直重發直到達到重發上限次數或者收到ACK。
快速重傳
當接收方收到的資料包是不正常的序列號,那麼接收方會重複把應該收到的那一條ACK重複傳送,這個時候,如果傳送方收到連續3條的同一個序列號的ACK,那麼就會啟動快速重傳機制,把這個ACK對應的傳送包重新發送一次。具體可以參考:
三 常見問題與措施
3.1單臺機器或單個應用機器tcp重傳,可能是連結的伺服器或埠無法訪問
排查思路
# 1、抓1000或者更多個tcp包 # 出現2次以上seq一樣的包就是發生了重傳 # syn包重傳間隔是指數增加 # 已經建立了連結的tcp重傳間隔,參考RTO # 收到比較多ack重傳,一般說明資料包出現亂序,seq較大的先到達了目的端,傳送端收到3次sack會觸發立即快速重傳缺失的tcp分片。快速重傳不太影響rt,但是傳送視窗立即減半,會對吞吐頻寬有一定影響 # 雲環境虛擬機器,還要考慮分析宿主機的問題 sudo ss -anti |grep -B 1 retrans #重傳統計 if=bond0 sudo tcpdump -w /tmp/tcp.pcap -i $if -c 1000 -nn tcp 2>/dev/null sudo tcpdump -nn -r /tmp/tcp.pcap | awk '{print $3,$5,$8,$9}' | sort | uniq -c | sort -rn|sed 's/^ \{1,\}//g'|egrep-v "^1 |Request" 2、聯通性檢查 ping $ip nc -nvz $ip $port 3、接收端應用程式問題排查;來源和目的抓包,wireshark分析具體是什麼包丟失導致了重傳
3.2 多臺機器或多個應用同時tcp重傳,可能是網路抖動
排查思路
1、檢視網路區域埋點,檢視網路裝置報警,看是否有區域網路抖動 2、區域網路沒問題的話。可以用常見問題:1 的方法縮小排查範圍
3.3 頻寬跑滿
排查思路
1、檢視主機監控,檢查是否頻寬跑滿 2、檢查重傳聯路上相關的網路裝置是否有頻寬跑滿
3.4 不常見問題
1 網路裝置埠或光模組異常等導致包checksum失敗
2 網路路由收斂抖動
3 主機網路驅動有bug,網路裝置有bug等
四 如何監控
使用tsar -tcp -C 可以監控到tcp的retran屬性也即是重傳次數。
tsar --tcp -C | sed 's/:/_/g;s/=/ /g' | xargs -n 2
感興趣的朋友可以直接執行以下監控指令碼獲取tcp相關的狀態監控資料,適用於open-falcon。
#!/usr/bin/env bash HOSTNAME=`hostname` timestamp=`date +%s` tagapp="app=tsar.collect" data_item="" tsarcollectstring=`/opt/tsar/bin/tsar --tcp -C | sed 's/:/_/g;s/=/ /g' | xargs-n 2 | tail -n +2|sed 's/ /|/'` for i in $tsarcollectstring do getkey=`echo $i|awk -F "|" '{print $1}'` getvalue=`echo $i|awk -F "|" '{print $2}'` tags="$tagapp" metric="tsar.collect.$getkey"
metric_item= "{ \" endpoint \" : \" ${HOSTNAME} \" , \" tags \" : \" ${tags} \" ,
\" timestamp \" :${timestamp}, \" metric \" : \" $metric \" ,
\" value \" :${getvalue}, \" counterType \" : \" GAUGE \" ,
\" step \" :60}"
if [ "${data_item}x" = "x"];then
data_item=
"$metric_item"
else
data_item="${data_item},${metric_item}"
fi
done
echo
"[$data_item]"
五 案例實踐
1 在遇到丟包重傳的機器上抓包並使用wireshark 分析該包,注意因為重傳不是時刻都有的,所以抓包命令是要持續執行以便捕捉到重傳的包。使用wireshark開啟tcpdump的結果,在搜尋框裡入手 tcp.analysis.retransmission 得到如下結果:
圖1 表明服務端發生了三次重傳動作。
2 由於包比較多,我們可以使用wireshark的 追蹤流功能 獲取重傳相關的tcp流
圖二 追蹤流-->TCP流 可以得到重傳相關的資料包
圖三 可以看出客戶端和服務端的請求與應答。
3 解析重傳
特別需要說明的是
NO 67,68 client端由於某些原因沒有收到正確的包資料,向server端傳送dup ack,參考基礎知識提到的 快速重傳
NO.68和NO.69之間的時間差200ms( 關注time那一列 ,其他都是相差小於1ms),server等待超時,於是重傳。
NO 73-74是client端傳送了一個fin包並主動關閉連線。
這個案例僅僅發生一次,沒有復現,通過抓包解析出來分析沒有得到明確的結論。
六 小結
本文 總結 自己工作過程中遇到的TCP重傳問題的解決過程 ,側重於大致的解決問題的思路與具體的實踐,理論知識偏少,大家有興趣的可以閱讀推薦文章以便深入瞭解tcp的工作機制。
推薦文章
tcp 重傳系列文章
https://www.cnblogs.com/lshs/p/6038516.html https://www.cnblogs.com/lshs/p/6038527.html https://www.cnblogs.com/lshs/p/6038536.html
網路效能排查之TCP重傳與重複ACK https://www.kancloud.cn/digest/wireshark/62473
一站式學習wireshark https://www.kancloud.cn/digest/wireshark
TCP重傳 http://www.vants.org/?post=36 本文有圖文介紹。