softirq(软中断)是Linux内核中的一种机制,将中断请求中不重要的部分从hardirq(硬中断)延后到softirq处理。当softirq负载较高时(任务数量过多或总处理时间过长),内核会将这些任务转移到名为ksoftirqd的percpu线程中执行,由调度器负责平衡该线程与其他用户任务之间的公平性。本文以Alibaba Cloud Linux 3系统为例介绍如何利用ksoftirqd进行延迟排查。
确认softirq延迟问题
下载bpftrace脚本至ECS实例任意目录下,例如
/tmp
。<tmp>
需替换为softirq_net_latency.bt
脚本存放的目录。sudo wget -P <tmp> https://gitee.com/dtcccccc/softirq_net_latency/raw/master/softirq_net_latency.bt
安装bpftrace。
sudo yum install -y bpftrace
执行以下命令,通过bpftrace来检测是否存在超过100ms的NET_RX类型的softirq延迟。
<tmp>
需替换为softirq_net_latency.bt
脚本实际所在目录。sudo bpftrace <tmp>/softirq_net_latency.bt 100000
如果脚本输出的延迟报告超过了100ms,则表明系统中存在softirq的延迟问题。
如果报告的进程名称(comm)为
ksoftirqd/$cpu
,则说明延迟是由于ksoftirqd线程得不到调度导致的。尽管softirq任务已被转移至普通优先级的ksoftirqd内核线程进行处理,但由于该线程处理任务所需时间相对较短,绝大部分时间处于睡眠状态,因此内核调度策略仍然倾向于优先调度该线程。在这种情况下,调度延迟依然显著,需对可能的异常情况进行排查,例如当前CPU上是否存在优先级更高的实时任务,或某个任务在内核态中耗时过长,导致ksoftirqd内核线程无法获得调度等。
如果不属于上述场景,则表明softirq正在中断上下文中运行,并且之前的hardirq执行时间过长(此情况极为罕见),需对内核及驱动进行排查。
使用top工具查看对应CPU上的hardirq占比,可以确认到该CPU上的hardirq占比较高。
通过监控
/proc/interrupts
文件的内容变化(该文件会展示系统启动以来每种中断在每个CPU上的触发总次数,用户可以隔一小段时间取样来对比差异)查看哪些中断在目标CPU上的触发次数增多,从而进一步排查对应设备的驱动。
配置ftrace记录系统日志
下载
softirq_ftrace.patch
补丁文件至softirq_net_latency.bt
脚本所在目录。<tmp>
需替换为softirq_net_latency.bt
脚本所在目录。sudo wget -P <tmp> https://gitee.com/dtcccccc/softirq_net_latency/raw/master/softirq_ftrace.patch
配置ftrace收集必要的系统信息。
sudo sh -c 'echo "irq:softirq_raise irq:softirq_entry sched:sched_switch sched:sched_wakeup raw_syscalls:sys_enter raw_syscalls:sys_exit" > /sys/kernel/debug/tracing/set_event' sudo sh -c 'echo 1 > /sys/kernel/debug/tracing/tracing_on'
开启ftrace日志记录,捕获到softirq高延迟时关闭日志记录。
<tmp>
需替换为softirq_net_latency.bt
脚本所在目录。cd <tmp> sudo patch -p1 < <tmp>/softirq_ftrace.patch sudo bpftrace --unsafe <tmp>/softirq_net_latency.bt 100000
异常诊断分析
以bpftrace打印以下报告为例,进一步跟踪cpu11上的ksoftirqd线程调度异常。
High IRQ-to-softirq latency: 132169 usec (132 ms) on CPU:11 comm:ksoftirqd/11
通过日志里的时间戳(单位为秒)可以观察softirq_raise与softirq_entry间隔较远的那一次,记录下对应时间戳,然后进入trace日志分析调度事件。
vec=3
表示网络类型的软中断。sudo su cd /sys/kernel/debug/tracing/per_cpu/cpu11/ grep "vec=3" ./trace
参考以下排查方向。
日志最左侧为当时正在执行的任务,观察目标时间戳范围期间正在执行的任务。通过
chrt -p $pid
命令查看任务的调度策略,如果为SCHED_DEADLINE、SCHED_FIFO或SCHED_RR,则说明该任务优先级高于普通任务(包括ksoftird内核线程),因此ksoftird被压制得不到调度。如果任务的优先级不在上述范围内,则说明它也同属于普通进程。需要考虑该任务可能陷入内核态的时间过长。在日志中表现为:在较长时间范围内,当前进程持续为该任务,且未发生任何调度切换。另一个常见现象是
syscall_enter
事件与其对应的syscall_exit
之间的跨度较大,覆盖了整个不发生调度切换的时间。在这种情况下,应结合任务的具体行为以及所调用的syscall
进行深入分析以确定原因。如果trace日志中提示当前进程属于SCHED_OTHER/SCHED_NORMAL普通优先级,并且没有持续很久的系统调用,甚至发生过调度切换到其他普通进程,则应考虑内核调度器可能存在某些异常。请联系我们并提供上述信息,以便进行进一步排查。