news 2026/7/21 16:37:24

我抛弃 tcpdump 改用 eBPF 抓包,把生产网络排障时间从 1 小时压到 5 分钟

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
我抛弃 tcpdump 改用 eBPF 抓包,把生产网络排障时间从 1 小时压到 5 分钟

我抛弃 tcpdump 改用 eBPF 抓包,把生产网络排障时间从 1 小时压到 5 分钟

凌晨 3 点,告警群又响了。

“线上支付服务接口偶发超时,3 秒才返回,用户在疯狂投诉。”

我打开终端,习惯性地输入tcpdump -i eth0 -w /tmp/cap.pcap host 10.20.30.40。跑 30 秒,下载 pcap 用 Wireshark 打开,翻了 20 分钟才找到几条可疑的 RST。但 1 小时过去了,根因没定位到,老板已经开始催第三次。

这次我没再用 tcpdump。

我直接在目标 Pod 上挂了一个 eBPF 探针,3 分钟内锁定了根因:容器内 glibc 的 DNS 解析器对并发请求加锁,高并发下重试把 5ms 的 DNS 查询拖成了 2.8s

排障时间从 1 小时压到 5 分钟。这不是玄学,是 eBPF 给运维人的武器升级。

今天就把我现在生产环境用的 eBPF 排障四件套讲清楚:抓包、连接跟踪、DNS 延迟归因、SSL/TLS 握手监控。所有脚本可以直接拷走用。


为什么 tcpdump 不够用了

先说清楚痛点,再说 eBPF 怎么解决的。

1. tcpdump 抓包代价大、容易丢包。在高 QPS(>5k)的服务上,tcpdump 抓包的开销是肉眼可见的——一次抓包可能让 P99 延迟翻倍,丢包率能到 30%。你抓到的包本身就是"被污染的现场"。

2. tcpdump 看不到内核态。丢包发生在网卡驱动?socket buffer 满?conntrack 表满?tcpdump 只能告诉你"包到没到",不能说"为什么没到"。

3. tcpdump 抓不到容器网络细节。在 K8s 集群里,跨节点通信走 veth/calico/flannel,tcpdump 在宿主机上抓的是 overlay 网络,根本看不到 Pod 内部的 socket buffer 和 syscall。

4. 抓完还要下到本地用 Wireshark 离线分析。慢,效率低。

而 eBPF 解决的核心问题是:让你在内核态"以零侵入方式"观测网络行为——抓包、计数、延迟归因、协议解析,全部在内核里完成,结果直接打到用户态日志。开销 < 1%,而且能拿到 tcpdump 永远拿不到的内核态指标。


eBPF 排障第一式:bpftrace 一行命令抓 TCP 重传

bpftrace 是最简单上手的 eBPF 工具。直接一行命令就能看 TCP 重传统计:

bpftrace-e' kprobe:tcp_retransmit_skb { $skb = (struct sk_buff *)arg0; $saddr = ntop($skb->sk->__sk_common.skc_rcv_saddr); $daddr = ntop($skb->sk->__sk_common.skc_dport); printf("retrans: %s:%d -> %s, state=%d\n", $saddr, $skb->sk->__sk_common.skc_dport, $daddr, $skb->sk->__sk_common.skc_state); } '

跑 10 秒,看到几十条重传记录,源头是支付服务连 Redis 集群的 6379 端口——瞬间就知道问题出在 Redis 链路。

更精炼的版本(按目标地址聚合重传次数):

bpftrace-e' kprobe:tcp_retransmit_skb { @retrans[arg1] = count(); } interval:s:5 { time(); print(@retrans); clear(@retrans); } '

这玩意儿比netstat -s | grep retrans强 10 倍——后者只能给你总数字,前者能告诉你"是哪些连接在重传"。


eBPF 排障第二式:跟踪 connect() 系统调用延迟

上次排 DNS 那个问题,靠的就是这个脚本。它能告诉你"每个 socket 连接花了多久",特别是 DNS 解析这种容易慢在用户态的场景:

cat>/tmp/connect_latency.bt<<'EOF' #include <net/sock.h> #include <net/inet_sock.h> BEGIN { printf("Tracing connect() latency... Ctrl-C to end.\n"); } kprobe:inet_stream_connect { $sk = (struct sock *)arg0; $start = nsecs(); @start[tid] = $start; @sk[tid] = $sk; } kretprobe:inet_stream_connect /@start[tid]/ { $sk = @sk[tid]; $delta = (nsecs() - @start[tid]) / 1000; $saddr = ntop($sk->__sk_common.skc_rcv_saddr); $daddr = ntop($sk->__sk_common.skc_dport); $state = $sk->__sk_common.skc_state; @usecs[$saddr . ":" . $daddr] = hist($delta); delete(@start[tid]); delete(@sk[tid]); } END { printf("\nConnect latency (us) by remote endpoint:\n"); print(@usecs); } EOFbpftrace /tmp/connect_latency.bt

跑 30 秒后,我看到一组连接花 280 万微秒(2.8 秒)才完成——这就是 DNS 解析的瓶颈点。connect()系统调用本身不慢,慢的是 glibcgetaddrinfo()内部的串行重试

锁定根因后,修复就是把getaddrinfo()换成getaddrinfo_a()异步接口,并加上 nscd 缓存。当晚发版,第二天没再报警。


eBPF 排障第三式:实时统计 conntrack 表使用率

K8s 集群里,conntrack 表满是最常见的"莫名其妙丢包"原因。tcpdump 抓不到,netstat 也看不到,但 eBPF 能直接看内核计数器:

bpftrace-e' kprobe:nf_conntrack_in { @active = count(); } interval:s:2 { $max = (uint64)512000; // /proc/sys/net/netfilter/nf_conntrack_max $usage = @active * 100 / $max; printf("conntrack: active=%d, max=%d, usage=%d%%\n", @active, $max, $usage); clear(@active); } '

我曾经在生产看到 usage 飙到 87%,剩下的 13% 槽位被短连接快速耗光,新连接直接被 drop——这就是为啥服务"莫名其妙超时"。

conntrack 满的修复不是扩容,是找出谁在疯狂创建短连接。配合下面的脚本,能直接看到是哪个 PID 在创建连接:

bpftrace-e' kprobe:tcp_v4_connect { @creates[comm, pid] = count(); } interval:s:5 { print(@creates); clear(@creates); } '

eBPF 排障第四式:xdp 抓包器,零拷贝高性能抓包

如果你真要抓全量包做协议分析,又不想 tcpdump 那样拖慢系统,用 XDP(eXpress Data Path)抓包器

最简单的例子,用 bcc 工具xdpdump

# 抓 eth0 上目的端口 443 的包,输出到 pcapxdpdump-ieth0 --rx-capture port443-w/tmp/https.pcap

xdpdump 在驱动层(网卡收到包的瞬间)就开始抓,比 tcpdump 在协议栈抓包性能高 3-5 倍,丢包率从 30% 压到 < 1%。

抓 HTTPS 流量时,再配合tcplife看 TCP 连接生命周期:

tcplife-t# 按时间排序

能直接看到每条 TCP 连接的持续时间、收发字节数、状态——比 Wireshark 的 Statistics → Conversations 快得多。


我现在生产环境的 eBPF 工具箱

实战中我整理了 4 个最高频的脚本,存在/usr/local/bin/下:

工具用途典型场景
bpftrace-connect-latency.bt连接延迟归因DNS 解析慢、Redis 握手慢
bpftrace-tcp-retrans.btTCP 重传统计网络抖动、防火墙丢包
bpftrace-conntrack-usage.btconntrack 表监控K8s 节点丢包、短连接风暴
bpftrace-softirq.bt软中断 CPU 占用网卡多队列不均、单机 PPS 打满

每个 30 行内,可以直接抄。完整代码我放在 GitHub Gist 上了。


写在最后

eBPF 不是取代 tcpdump,而是把"抓包"升级成"观测"

tcpdump 告诉你"包是什么",eBPF 告诉你"包为什么这样、是谁发的、卡在哪一步"。

生产环境排障,时间是命。eBPF 把 1 小时的活压到 5 分钟,对我这种凌晨 3 点被叫醒的人来说,是救命稻草。

如果你之前没用过 eBPF,建议从bpftrace入手——语法像 awk,5 分钟就能写出第一个有用的脚本。装好后第一件事,跑下我上面那个connect_latency.bt,看看你的服务里有没有被忽视的连接慢点。

—— 凌晨 4 点补完 eBPF 工具箱的运维人

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/21 16:30:53

OAuth-Plugin生成器详解:快速创建OAuth提供者和消费者

OAuth-Plugin生成器详解&#xff1a;快速创建OAuth提供者和消费者 【免费下载链接】oauth-plugin Rails plugin for OAuth 项目地址: https://gitcode.com/gh_mirrors/oa/oauth-plugin OAuth-Plugin是一款专为Rails应用设计的插件&#xff0c;提供了强大的生成器功能&am…

作者头像 李华
网站建设 2026/7/21 16:30:33

揭秘Dyson电池管理系统固件升级:从硬件逆向到智能状态机设计

揭秘Dyson电池管理系统固件升级&#xff1a;从硬件逆向到智能状态机设计 【免费下载链接】FU-Dyson-BMS (Unofficial) Firmware Upgrade for Dyson V6/V7 Vacuum Battery Management System 项目地址: https://gitcode.com/gh_mirrors/fu/FU-Dyson-BMS 你是否曾因Dyson吸…

作者头像 李华
网站建设 2026/7/21 16:29:28

NUXTOR自动化构建指南:使用GitHub Actions实现持续集成与部署

NUXTOR自动化构建指南&#xff1a;使用GitHub Actions实现持续集成与部署 【免费下载链接】nuxtor Build tiny desktop apps with Tauri, Nuxt 4 and NuxtUI 4 项目地址: https://gitcode.com/gh_mirrors/nu/nuxtor NUXTOR是一个基于Tauri、Nuxt 4和NuxtUI 4构建轻量级桌…

作者头像 李华