博客 / 詳情

返回

中斷不控,延遲難穩:低延遲系統的終極痛點

一、引言

在金融交易、工業控制、高性能網絡等要求微秒級時延的系統中,“中斷”常常是影響尾延遲(Tail Latency)的關鍵因素之一。
在普通系統裏,中斷帶來的幾十微秒抖動並不算問題,但在低延遲系統中,即使是 幾微秒的不可控波動,都可能導致性能抖動、訂單錯失。
本文將從原理、影響、排查等維度,系統性介紹中斷對低延遲系統的影響。

二、低延遲系統的特點

低延遲系統的目標是在極短時間內完成處理,並保持響應時間高度穩定。這類系統通常有以下共性,使得它們對中斷格外敏感:

1. 強調確定性

低延遲系統不僅追求“快”,更追求“穩定”。它希望每一次響應時間都儘量一致,不出現無規律的波動。而中斷的觸發往往具有不確定性,會破壞這種穩定性。

2. 核心資源為業務專用

為了減少干擾,低延遲系統通常會預留部分 CPU 只運行核心業務邏輯。
任何外來的系統任務、中斷或調度行為進入這些核心,都會破壞業務線程的專注度,引發延遲尖刺。

3. 對尾延遲特別敏感

很多系統關注平均延遲,但低延遲系統還關注最差情況(例如 99.9%、99.99% 延遲)。
因此哪怕偶爾一次中斷引發幾十微秒的延遲,也會被放大成系統性能問題。

4. 對干擾高度敏感

低延遲系統通常關閉節能、規避搶佔、避免內核後台任務等。
在這種極限優化狀態下,即使是非常小的系統活動,例如一次定時器中斷,也可能打斷業務流程,從而產生可觀的抖動。

三、中斷如何影響低延遲系統?

中斷在低延遲系統中的影響主要體現在三個層面:

1. 搶佔執行、打斷業務線程

中斷會中止正在運行的業務代碼,引起:

  • CPU L1/L2 緩存污染
  • pipeline flush
  • TLB miss 增加
  • 業務線程指令亂序恢復

對於微秒級任務,這種打斷是“毀滅性”的。

2. 導致不可預測的時延尖刺

中斷不連續、不規則,例如:

  • 某個 IRQ 在負載高時突然 flood
  • 某個 housekeeping 定時器每幾秒被觸發
  • 某個軟中斷在 backlog 到閾值後被 forced 執行

這些都會導致業務端出現 幾微秒到幾十微秒的波動。

3. 軟中斷(SoftIRQ)更隱蔽

很多系統管理員只關注“硬中斷”,但真正殺傷力高的是:

  • NET_RX
  • NET_TX
  • TIMER
  • TASKLET
  • RCU

它們會在本 CPU 上被強制執行,且執行時長不可控,極容易破壞延遲穩定性。

四、如何排查中斷對延遲的影響?

在低延遲系統中,中斷是否落到了業務核心、是否存在異常增長,是判斷延遲抖動來源的關鍵依據。
傳統方式通常是直接 cat /proc/interrupts,但它不具備實時性,也難以觀察變化趨勢。
因此,使用自研的 irq_watch.py 腳本,實現實時監控中斷變化,幫助快速定位問題。

1. irq_watch.py 的功能概述

該腳本的核心作用是:

  • 實時監控指定 IRQ 或 CPU 的中斷增長情況

腳本每秒讀取 /proc/interrupts,計算變化量,只輸出“發生變化的項”。

  • 支持 CPU 或 IRQ 白名單篩選
    避免全量輸出帶來的噪聲。
  • 支持稀疏 CPU(如 CPU0/7/8/9/12)
    可自動解析實際在線 CPU,而不依賴連續編號。
  • 支持參數格式:1,5-7,10-12
    滿足生產環境中常見的範圍表達方式。
  • 附帶中斷描述信息
    如網卡 MSI-X、IPI、timer 等,便於快速識別來源
  • 兼容 Python 2 / Python 3
    適用於老舊發行版(如 RHEL7)。

    2. 參數説明

腳本提供三個最常用參數:

參數 説明
-irq 指定監控的 IRQ 號(支持範圍表達式)
-cpu 指定監控的 CPU 核(支持範圍表達式)
-i 刷新間隔,默認 1 秒

3. 示例

只監控 CPU0 與 CPU1 中斷情況

./irq_watch.py -cpu 0,1

監控特定中斷號(如 36、37、40–45)

./irq_watch.py -irq 36,37,40-45

監控多 CPU + 多 IRQ(組合過濾)

./irq_watch.py -cpu 0,7-9 -irq 33-50

4. 輸出示例解析

以下是監控cpu0和cpu1上每秒中斷的情況:

[root@instance-bguv65e0 ~]# ./irq_watch.py -cpu 0,1
2025-11-26 19:25:44
IRQ    37 CPU   0: +        10 (total  120514471)      PCI-MSIX-0000:02:00.0 1-edge virtio1-req.0
IRQ    38 CPU   1: +         5 (total  117021031)      PCI-MSIX-0000:02:00.0 2-edge virtio1-req.1
IRQ    45 CPU   0: +        13 (total   49011897)      PCI-MSIX-0000:01:00.0 1-edge virtio0-input.0
IRQ    46 CPU   0: +         5 (total   29506292)      PCI-MSIX-0000:01:00.0 2-edge virtio0-output.0
IRQ    47 CPU   1: +        13 (total   51737238)      PCI-MSIX-0000:01:00.0 3-edge virtio0-input.1
IRQ    48 CPU   1: +        21 (total   56302135)      PCI-MSIX-0000:01:00.0 4-edge virtio0-output.1
IRQ   LOC CPU   0: +       232 (total   41007210)      Local timer interrupts
IRQ   LOC CPU   1: +       186 (total  540671379)      Local timer interrupts
IRQ   CAL CPU   0: +         3 (total   26439851)      Function call interrupts
2025-11-26 19:25:45
IRQ    37 CPU   0: +         1 (total  120514472)      PCI-MSIX-0000:02:00.0 1-edge virtio1-req.0
IRQ    38 CPU   1: +         4 (total  117021035)      PCI-MSIX-0000:02:00.0 2-edge virtio1-req.1
IRQ    45 CPU   0: +         4 (total   49011901)      PCI-MSIX-0000:01:00.0 1-edge virtio0-input.0
IRQ    46 CPU   0: +         9 (total   29506301)      PCI-MSIX-0000:01:00.0 2-edge virtio0-output.0
IRQ    47 CPU   1: +         6 (total   51737244)      PCI-MSIX-0000:01:00.0 3-edge virtio0-input.1
IRQ    48 CPU   1: +         7 (total   56302142)      PCI-MSIX-0000:01:00.0 4-edge virtio0-output.1
IRQ   LOC CPU   0: +       234 (total   41007444)      Local timer interrupts
IRQ   LOC CPU   1: +       166 (total  540671545)      Local timer interrupts
IRQ   RES CPU   0: +         1 (total   16877997)      Rescheduling interrupts
IRQ   CAL CPU   0: +         3 (total   26439854)      Function call interrupts
2025-11-26 19:25:46
IRQ    45 CPU   0: +         4 (total   49011905)      PCI-MSIX-0000:01:00.0 1-edge virtio0-input.0
IRQ    46 CPU   0: +         8 (total   29506309)      PCI-MSIX-0000:01:00.0 2-edge virtio0-output.0
IRQ    47 CPU   1: +         5 (total   51737249)      PCI-MSIX-0000:01:00.0 3-edge virtio0-input.1
IRQ    48 CPU   1: +         4 (total   56302146)      PCI-MSIX-0000:01:00.0 4-edge virtio0-output.1
IRQ   LOC CPU   0: +       200 (total   41007644)      Local timer interrupts
IRQ   LOC CPU   1: +       204 (total  540671749)      Local timer interrupts
IRQ   RES CPU   0: +         7 (total   16878004)      Rescheduling interrupts
IRQ   RES CPU   1: +         2 (total   20872214)      Rescheduling interrupts
IRQ   CAL CPU   0: +         1 (total   26439855)      Function call interrupts

解釋如下:
IRQ:中斷號(或 LOC/CAL 等 IPI 名字)
CPU:發生增量的 CPU 核編號
+N:本次 interval 內增加多少次
total:累計總次數
描述:/proc/interrupts 最後一列,中斷來源(網卡/磁盤/IPI/timer)

監控的中斷數量沒有變化會輸出 (no change):

[root@instance-bguv65e0 ~]# ./irq_watch.py -irq 222
2025-11-26 19:44:35
no change
2025-11-26 19:44:36
no change
2025-11-26 19:44:37
no change

這樣可大幅降低無意義噪聲,便於觀察異常增長。

五、典型排查場景

場景 1:業務核心是否被“髒”中斷污染?

在延遲敏感的系統中,關鍵的業務線程往往會被綁定到固定的核心上,比如業務核心被綁定在 6,7,8,9號核心,則可以用以下指令來監測:

./irq_watch.py -cpu 6-9

場景 2:排查稀疏 CPU 佈局下的中斷落點

在禁用了部分核的系統中(如 CPU0/7/8/9/12 在線):

./irq_watch.py -cpu 7-12

腳本可自動識別真實在線 CPU,使排查更準確。

場景 3:觀察週期性延遲尖刺是否由某 IRQ 觸發

例如懷疑某個 timer 中斷:

./irq_watch.py -irq LOC

或懷疑某特點中斷

./irq_watch.py -irq 64-100

若被監控的中斷數量週期性增長,則可以確定延遲尖刺原因。

六、irq_watch.py 的優勢總結

能力 描述
實時檢測 定位瞬時 spike 不再困難
增量輸出 不輸出無變化項,噪聲極低
CPU/IRQ 雙過濾 靈活監控業務相關部分
稀疏 CPU 兼容 適配任意在線 CPU 佈局
自動提取中斷描述 快速識別來源
資源佔用低 佔用的硬件資源幾乎可以忽略

七、如何獲取?

📌 獲取方式如下:
1️⃣ 關注我的微信公眾號:Hankin-Liu的技術研究室
2️⃣ 發送關鍵詞:irq watch
3️⃣ 獲取腳本
4️⃣ 發送關鍵詞:”性能調優羣“,加入技術交流羣,可免費解答和交流性能調優相關技術問題。

八、總結

低延遲系統需要在高度可控、可預測的環境中運行,而中斷是影響系統確定性的關鍵因素之一。理解中斷在系統中的角色、其帶來的不確定性來源,以及如何持續監測其行為,是打造穩定低延遲系統的基礎能力。
通過構建完善的監控機制、結合業務特性制定相應策略,並持續驗證系統在實際負載下的表現,可以更好地確保低延遲系統在各種運行狀態下保持一致的性能表現。中斷管理不是一次性的工作,而是伴隨系統運行全週期的持續任務。

📬 歡迎關注VX公眾號“Hankin-Liu的技術研究室”,持續分享信創、軟件性能測試、調優、編程技巧、軟件調試技巧相關內容,輸出有價值、有沉澱的技術乾貨。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.