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