更多云服務器知識,盡在hostol.com
你有沒有遇到過這種情況?網站訪問卡頓,接口響應慢得像蝸牛爬。你 ping 服務器沒丟包,CPU 內存也沒打滿,日志也沒報錯,結果就是不知道哪兒出的問題。
你用抓包分析,Wireshark 打開后一臉懵——各種 ACK、SYN、FIN,你看得頭暈眼花。
最后,你懷疑人生,甚至開始懷疑是不是 DNS 解析的鍋。
但其實,幕后真兇可能就是:TCP 重傳。
而要真正揪出這個重傳元兇,你光靠抓包和傳統監控工具根本不夠。你需要更深一層的“系統級透視”——這時候,eBPF 上場了。
什么是 TCP 重傳?為什么它是“隱形殺手”?
TCP 重傳(TCP Retransmission)指的是發送方在一定時間內沒有收到 ACK 確認,就會重新發送之前的數據包。
它的本意是好的:防止丟包影響通信。但當重傳頻繁出現,就不是“善意提醒”了,而是性能災難。
為什么?
- 它會 增加延遲,尤其是在 BBR 擁塞控制中;
- 它會 占用帶寬,導致正常請求變慢;
- 它會 引發業務超時,比如 RPC 調用卡死;
- 它 不會輕易暴露錯誤,不會直接報錯,只是“慢”。
這才是最要命的地方:你以為是網絡抖了,結果是 TCP 抖得不行。
傳統方法:抓包 + ifconfig + ss,哪里卡?
我們來看一下傳統排查 TCP 重傳的方法:
🧪 方法一:抓包
bash
tcpdump -i eth0 tcp -w /tmp/tcp.pcap
然后拿去 Wireshark 打開,看統計 - TCP 分析。
問題:
- 只能看到發生了重傳,但看不到是哪個服務引起的;
- 無法按進程粒度判斷;
- 不能實時監控,太重、太繁瑣。
🧪 方法二:ss
+ netstat
bash
ss -s
netstat -s | grep retrans
問題:
- 粒度粗,統計信息大雜燴;
- 看不到“是誰”造成的重傳;
- 無法分服務、分 socket 追蹤。
這就像醫生告訴你“你體溫高了”,但不給你查是哪里發炎。
真正的王炸工具:eBPF!
eBPF(extended Berkeley Packet Filter)是 Linux 內核的一項黑科技,能讓你在內核里掛鉤各種事件,比如網絡收發、系統調用、調度器、socket 操作等等。
我們可以用它做到以下事情:
- 跟蹤每個 TCP socket 的重傳行為;
- 把“哪個進程、哪個端口、哪個遠程 IP”全都釘出來;
- 實時把數據導入 Prometheus / Grafana 監控;
- 不需要修改內核代碼,運行時動態加載。
簡直是“系統級顯微鏡”。
eBPF 實戰:抓 TCP 重傳的最強組合(實操指南)
這里我們用 bcc(BPF Compiler Collection)和 bpftrace 兩種方式來做。
? 方式一:用 tcprtt
監控 TCP 往返延遲 & 重傳
安裝 bcc:
bash
sudo apt install bpfcc-tools linux-headers-$(uname -r)
執行:
bash
sudo /usr/share/bcc/tools/tcpretrans
它會輸出以下內容:
nginx
PID COMM LADDR LPORT RADDR RPORT RETRIES
1324 nginx 192.168.1.20 443 10.0.0.15 54120 2
是不是一目了然?誰在重傳,一清二楚。
你還可以加參數按需過濾:
bash
tcpretrans -p 1324 # 查看某個進程
tcpretrans -t 60 # 每隔 60 秒刷新一次
? 方式二:用 bpftrace
自定義更精細的探針
比如,我們想追蹤 kernel 中的 tcp_retransmit_skb 函數調用:
bash
sudo bpftrace -e 'kprobe:tcp_retransmit_skb { @[kstack] = count(); }'
它會告訴你,重傳事件在哪個內核調用棧上發生最多。進階玩法還包括統計頻率、匹配 IP、打印時間戳等。
你可以結合以下 tracepoints:
tcp:tcp_retransmit_skb
tcp:tcp_probe
sock:sock_exceed_memory_limits
net:net_dev_queue
把探針數據接入監控平臺:Grafana 可視化
你還可以把這些數據導入 Prometheus:
- 用
bpfd-exporter
導出 bcc 指標; - 使用 Grafana 創建 TCP Retrans Dashboard;
- 配置告警,比如“某進程重傳率連續 5 分鐘 > 2%”;
這樣,你就有了一個實時的 TCP 重傳監控體系,分分鐘揪出“悶聲做惡”的慢服務。
實戰案例分享:一個 nginx 負載均衡節點引發的血案
某公司后臺 API 服務平均響應時長從 60ms 突然飆升至 900ms,但沒有丟包、沒有超時日志。排查了半天,最終用 tcpretrans
發現:
nginx
PID COMM LADDR LPORT RADDR RPORT RETRIES
4456 nginx 10.10.1.3 443 10.10.2.50 60812 5
原來是某個 nginx 負載均衡節點由于網卡驅動 bug,導致大量 ACK 包丟失,服務不斷重傳。
直接替換機器,問題瞬間解決。
傳統手段壓根沒辦法發現這個細節。
網絡瓶頸的“真相鏈”:不是延遲高,而是 TCP 抖
很多時候我們以為:
慢,是服務器慢,或者用戶網絡差。
但實際上:
很多“慢”來自 TCP 層級的重傳,它沒報錯,但拖慢了整個請求流程。
特別是在高并發場景下,重傳不僅僅影響個別用戶,而是整個系統的吞吐量都會被打壓。
- 應用沒變,CPU 沒飆,RT 卻一直在漲;
- 日志沒報錯,鏈路全綠,用戶卻在罵卡;
- 部署集群一樣,但某節點異常重傳成瓶頸。
這些,傳統監控是看不到的,你需要用 eBPF 去“抽絲剝繭”。
深度治理建議:只抓重傳還不夠,還要搞清它為啥重傳
監控發現重傳只是第一步,你還需要定位原因。常見幾種元兇:
?? 網絡側:
- 交換機丟包(緩存不足)
- MTU 配置不一致,造成分片異常
- VPN 加密鏈路 jitter
?? 系統側:
- 應用線程阻塞,發送不及時
- socket backlog 滯后
- Linux 內核參數不合理(比如擁塞控制算法)
建議配合以下內核參數調整:
bash
net.ipv4.tcp_retries2 = 5
net.ipv4.tcp_sack = 1
net.ipv4.tcp_congestion_control = bbr
高階玩法:自動探針 + 多集群溯源
你可以封裝一個腳本,把 tcpretrans 的輸出匯總為 JSON:
bash
#!/bin/bash
tcpretrans -j | jq > /var/log/tcp_retrans.json
然后通過 Promtail 推送到 Loki,Grafana 做自動可視化,配合:
- 服務名 → IP → 重傳率
- 請求路徑 → 平均RT → 重傳異常點
- 節點對比圖 → 一圖揪出異常機器
這就是完整的“TCP 重傳自動溯源系統”。
最后說一句:別再盯著 CPU 和內存了,真正影響用戶體驗的,有時候只是你沒看到的一個包。
傳統監控是看 CPU、看內存、看負載。
但真正造成接口卡頓的元兇,往往隱藏在 TCP 棧內部的微抖動中。
eBPF 就像是“X 光”,幫你透視內核、還原真相。
所以,下次你的系統突然卡頓,別只問“CPU 有沒有打滿”,而是試著問:
“是不是誰在悄悄重傳?”