ksoftirqd延迟排查说明

softirq(软中断)是Linux内核中的一种机制,将中断请求中不重要的部分从hardirq(硬中断)延后到softirq处理。当softirq负载较高时(任务数量过多或总处理时间过长),内核会将这些任务转移到名为ksoftirqd的percpu线程中执行,由调度器负责平衡该线程与其他用户任务之间的公平性。本文以Alibaba Cloud Linux 3系统为例介绍如何利用ksoftirqd进行延迟排查。

确认softirq延迟问题

  1. 下载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
  2. 安装bpftrace。

    sudo yum install -y bpftrace
  3. 执行以下命令,通过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执行时间过长(此情况极为罕见),需对内核及驱动进行排查。

      1. 使用top工具查看对应CPU上的hardirq占比,可以确认到该CPU上的hardirq占比较高。

      2. 通过监控/proc/interrupts文件的内容变化(该文件会展示系统启动以来每种中断在每个CPU上的触发总次数,用户可以隔一小段时间取样来对比差异)查看哪些中断在目标CPU上的触发次数增多,从而进一步排查对应设备的驱动。

配置ftrace记录系统日志

  1. 下载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
  2. 配置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'
  3. 开启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

异常诊断分析

  1. 以bpftrace打印以下报告为例,进一步跟踪cpu11上的ksoftirqd线程调度异常。

    High IRQ-to-softirq latency: 132169 usec (132 ms) on CPU:11 comm:ksoftirqd/11
  2. 通过日志里的时间戳(单位为秒)可以观察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普通优先级,并且没有持续很久的系统调用,甚至发生过调度切换到其他普通进程,则应考虑内核调度器可能存在某些异常。请联系我们并提供上述信息,以便进行进一步排查。