更多云服务器知识,尽在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 有没有打满”,而是试着问:
“是不是谁在悄悄重传?”