ksoftirqd占用高但NET_RX正常,说明问题在BLOCK或TIMER softirq而非网络接收路径;需通过/proc/softirqs变化速率、/proc/irq/*/spurious、perf trace及存储设备状态等综合定位根因。

为什么 ksoftirqd 占用高但 net_rx softirq 统计正常
这通常意味着问题不在网络接收路径本身,而是其他 softirq 类型(尤其是 block 或 timer)在持续触发、排队或执行时间过长,导致 ksoftirqd 线程忙于处理 backlog。注意:/proc/softirqs 中的 NET_RX 计数只反映被触发次数,不反映单次执行耗时;即使它增长平缓,只要某次 block softirq 处理花了 20ms,就可能阻塞后续所有 softirq 调度,ksoftirqd 就会持续跑满。
确认到底是 block 还是 timer softirq 在作祟
直接看 /proc/softirqs 各列累计值变化速率:
watch -n1 'grep -E "^(BLOCK|TIMER)" /proc/softirqs'
更关键的是观察每 CPU 的实时 pending 和延迟:
-
cat /proc/irq/*/spurious—— 查看是否有异常中断风暴(尤其 SCSI/NVMe 驱动 bug 可能引发虚假中断 → 触发大量TIMERsoftirq) -
perf record -e irq:softirq_entry -g -- sleep 5+perf script | grep -E "(block|timer)"—— 定位实际进入 softirq 的调用栈源头 - 检查
/sys/block/*/stat是否有某设备io_ticks暴涨但reads_completed几乎不动 —— 典型 IO hang 导致BLOCKsoftirq 卡住
block softirq 卡住的常见根因和验证方式
BLOCK softirq 主要由块设备驱动在完成 IO 后触发(如 blk_mq_complete_request),卡住往往不是软中断本身慢,而是它依赖的上下文被阻塞:
- 文件系统层锁竞争:比如 XFS 的
log wait或 ext4 的journal commit持久阻塞,用cat /proc/fs/xfs/xfsstats | grep xs_log_waits或dmesg -T | grep -i "journal.*wait"查 - 底层存储响应超时:NVMe 设备掉盘、RAID 卡降速、iSCSI target 延迟突增,用
smartctl -a /dev/nvme0n1、cat /sys/class/scsi_host/host*/stat、iscsiadm -m session -P 3排查 - IO 调度器死锁:CFQ 已淘汰,但某些定制内核仍用,或
mq-deadline在高队列深度下出现请求合并异常,临时切到none测试:echo none > /sys/block/nvme0n1/queue/scheduler
timer softirq 异常升高的典型场景
TIMER softirq 占用高,大概率不是定时器太多,而是某个 timer handler 执行太久,或 timer 频繁重调度形成“timer storm”:
- 用户态进程频繁调用
nanosleep、epoll_wait(带 timeout)、select,且 timeout 极短(如 1ms),内核需为每个调用注册/注销高精度 timer —— 用perf record -e 'syscalls:sys_enter_nanosleep' -- sleep 2抓嫌疑进程 - 内核模块 bug:比如某些旧版 RDMA 驱动、DPDK PMD、或自研驱动在
mod_timer时传入已销毁的 timer 结构体,导致 softirq 循环重试 - RCU stall 间接引发:当 RCU callback 积压,内核会通过
TIMERsoftirq 强制推进,查dmesg | grep -i "rcu.*stall"和/proc/sys/kernel/rcu_normal值
真正难排查的是 softirq 在不同 CPU 间迁移不均 + 某个 CPU 上 block/timer handler 有隐式锁等待,这时候单看统计值会误判,必须结合 perf sched latency 和 per-CPU 的 /proc/softirqs 快照交叉比对。










