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普通優先級,并且沒有持續很久的系統調用,甚至發生過調度切換到其他普通進程,則應考慮內核調度器可能存在某些異常。請聯系我們并提供上述信息,以便進行進一步排查。