dropwatch 是一款专门用于定位 Linux 内核协议栈丢包 的工具,它通过监听 kfree_skb 事件,实时捕获数据包在内核中被丢弃时的函数调用栈,从而精确定位丢包发生的内核代码位置。以下是结合真实场景的故障定位使用案例汇总。
一、工具原理与适用场景
核心原理
dropwatch 利用内核的 kprobe 或 tracepoint 机制,挂钩到 kfree_skb() 函数——这是内核释放(丢弃)网络数据包(sk_buff)的必经之路 。当丢包发生时,它会记录当时的内核调用栈,并通过 /proc/kallsyms 将内存地址解析为人类可读的函数名,最终输出一张内核丢包热点地图。
适用场景
1、应用日志无报错,但用户反馈访问慢、连接超时
2、ifconfig/ethtool 显示有丢包,但无法定位具体原因
3、需要区分正常释放与异常丢弃(TCP 成功交付后也会调用 kfree_skb)
二、安装部署
# 克隆源码 git clone https://github.com/pavel-odintsov/drop_watch.git cd drop_watch/src
# 安装依赖(RHEL/CentOS) sudo yum install-y kernel-devel-$(uname-r) libnl3-devel binutils-devel
yum install -y dropwatch 或 dnf install -y dropwatch
# 安装依赖(Ubuntu/Debian) sudoapt-getinstall-y linux-headers-$(uname-r) libnl-3-dev libnl-genl-3-dev binutils-dev libreadline-dev
# 编译安装 make sudocp dropwatch /usr/local/bin/
|
三 核心命令
1. 启动命令
| 命令 | |
| start | |
| |
| |
| |
| |
| |
| 捕获N个丢包后自动停止(如set alertlimit 100) |
| set alertmode summary/packet | |
| |
| |
2. 限制监控数量
| sudo dropwatch -l kasdropwatch> set alertlimit 50# 捕获50个丢包后自动停止dropwatch> start |
3. 仅监控软件/硬件丢包
| # 仅软件丢包dropwatch> set swdropwatch> start# 仅硬件丢包(网卡硬件层面)dropwatch> set hwdropwatch> start |
4. 结合perf进一步定位
| # 捕获skb释放事件(丢包核心事件)perf record -g -a -e skb:kfree_skb# 查看调用栈perf report |
三、实战案例
案例 1:内核协议栈内存不足丢包
现象:系统出现间歇性网络中断,netstat -s | grep reassembles 显示大量分片重组失败。
排查过程:
1、运行 dropwatch 持续监控,发现大量丢包集中在 ip_frag_reasm 和 ip_expire 相关调用栈。
2、结合 dmesg 发现报错:inet_frag_find: Fragment hash bucket 128 list length grew over limit. Dropping fragment.
3、确认是系统内存不足,导致创建新分片队列失败。
解决方案:
# 增大网络内存缓冲区 sysctl-wnet.core.rmem_default=31457280 sysctl-wnet.core.rmem_max=33554432 sysctl-wnet.ipv4.ipfrag_high_thresh=...
|
案例 2:Netfilter/iptables 规则误杀
现象:特定端口的服务偶发连接失败,抓包显示客户端 SYN 到达但无响应。
排查过程:
1、dropwatch 捕获到大量丢包调用栈顶部为 nf_hook_slow 。
2、进一步使用 bpftrace 追踪 nf_hook_slow 耗时,确认防火墙规则处理逻辑。
3、检查 iptables -L -n -v 发现存在一条隐蔽的 DROP 规则匹配了该服务端口。
结论:dropwatch 精准定位到丢包发生在 Netfilter 框架,避免了在应用层无意义的排查。
案例 3:TCP 接收缓冲区满导致丢包
现象:高并发场景下,服务端出现 TCPBacklogDrop 计数增加。
排查过程:
1、dropwatch 输出显示丢包集中在 tcp_v4_do_rcv → sk_filter_trim_cap 路径。
2、结合 nstat 确认 TcpExtTCPRcvQDrop 持续增长 。
3、判断为应用层读取速度慢于数据包到达速度,导致 socket 接收缓冲区溢出。
解决方案:
# 调整 socket 缓冲区 sysctl-wnet.core.rmem_max=16777216 # 应用层优化:增大 listen backlog 或优化读取逻辑
|
案例 4:定位iptables丢包
| # 1. 启动监控sudo dropwatch -l kasdropwatch> start# 2. 触发流量(如访问被拦截端口)# 3. 观察输出:大量 nf_hook_slow 丢包10 drops at nf_hook_slow+f3 (0xffffffff92a99be3)# 4. 排查iptables规则iptables -L -n -v# 查看是否有DROP规则 |
四、dropwatch 输出解读示例
$ sudo dropwatch -l kas Initalizing kallsyms db dropwatch> start Enabling monitoring... Kernel dropped packets at: tcp_v4_rcv+0x1a3 (0xffffffff8176a2a3) ip_local_deliver_finish+0x5f (0xffffffff8174e45f) ip_local_deliver+0xba (0xffffffff8174e3ba) ip_rcv_finish+0x89 (0xffffffff8174d089) netif_receive_skb_internal+0x45 (0xffffffff8173c045) 1 packets dropped at location 0xffffffff8176a2a3
|
解读要点:
1、tcp_v4_rcv+0x1a3:丢包发生在 TCP 接收处理函数
2、需结合 kfree_skb 的 drop_reason(Linux 5.18+)判断是否为异常丢弃
五、配合工具链
六、注意事项
1、正常 vs 异常丢包:kfree_skb 在 TCP 成功交付后也会被调用释放资源,需结合调用栈和 drop_reason 区分 。
2、符号解析:生产环境务必安装 kernel-debuginfo,否则无法解析函数名 。
3、性能开销:dropwatch 单次事件开销约 100ns,对正常业务影响极小,但在极高丢包率场景下需注意