网络栈调优98 条

内核丢包点追踪

怀疑协议栈内部丢包时, 追踪 skb:kfree_skb 丢弃原因, 直接定位丢在哪个子系统。

内核丢包点追踪

接口计数只能告诉你「丢了多少」,不能告诉你「丢在哪一步」。当怀疑协议栈内部丢包时,可以追踪 skb 释放的时机:在 kfree_skb 上统计丢弃原因或记录调用栈,直接定位到具体子系统。较新内核在该追踪点提供了丢弃原因字段,老内核则需要依靠调用栈推断。

基本信息

工具bpftrace、perf 等基于内核追踪点的工具
追踪点tracepoint:skb:kfree_skb
原因字段较新内核提供 reason 参数,旧内核无此字段
替代方式旧内核用 kprobe:kfree_skb 配合调用栈统计
开销与命中次数成正比,需限定时间窗与过滤条件

典型使用场景

  • 接口计数显示丢包,但网卡侧没有丢弃记录,怀疑丢在协议栈内部
  • 连接跟踪表满导致的丢包定位
  • 路由或策略丢弃的确认,例如被防火墙规则拦下
  • 发送队列满导致的丢弃,与队列统计互相印证
  • 内核升级前后对比丢弃原因分布的变化

统计丢弃原因

统计丢弃原因
bpftrace -e 'tracepoint:skb:kfree_skb { @[args->reason] = count(); }'
# 旧内核没有 reason 字段时,改用调用栈统计:
bpftrace -e 'kprobe:kfree_skb { @[kstack(5)] = count(); }'
# 只观察特定地址的丢弃:在表达式中加入地址过滤再统计

常见丢弃来源

丢弃位置典型原因排查方向
连接跟踪表容量达到上限查看条目数与上限水线
路由与策略无可用路由或被规则拒绝核对路由表与策略配置
发送队列队列已满查看 qdisc 统计与队列长度
接收路径内存不足或校验失败检查内存压力与网卡计数

使用注意

  • 先限定时间窗与流量条件,避免全量统计带来不可控开销
  • 在测试环境先验证脚本写法,再用于生产观测
  • 原因枚举随内核版本演进,解读时以本机内核为准
  • 把追踪结果与接口计数、队列统计相互印证
长期在线全量统计不适合做为常态监控:追踪点命中次数与流量成正比,在丢包严重的故障机上反而会加重负担,应限定窗口并按需启用。
在无 reason 字段的内核上照搬新写法会直接报错;确认内核是否支持该字段最省事的办法是查看追踪点定义,而不是凭版本号猜测。

易错点

  • 长期在线全量统计,观测开销不可控,反而加重故障主机负担
  • 在无 reason 字段的内核上照搬新写法,脚本直接报错
  • 只看丢弃原因不看调用栈,无法确认是哪个子系统触发的
  • 把追踪结果当成唯一证据,未与接口计数和队列统计交叉验证

数据来源与参考

  • 内核 tracepoint 定义 include/trace/events/skb.h
  • bpftrace 手册
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌