卡多隊列 RSS 與 CPU 軟中斷親和性綁定實戰(zhàn):徹底解決單核中斷打滿瓶頸)
網(wǎng)卡多隊列 RSS 與 CPU 軟中斷親和性綁定實戰(zhàn)徹底解決單核中斷打滿瓶頸在很多配置了萬兆網(wǎng)卡與上百物理核心的高性能服務(wù)器上經(jīng)常上演一幕極其荒誕的性能災(zāi)難用監(jiān)控工具查看整機平均 CPU 利用率只有微不足道的 3% 到 5%上游服務(wù)卻頻繁報警“連接超時、TCP 丟包嚴重”敲下ifconfig或ethtool -S網(wǎng)卡的rx_dropped與rx_discards計數(shù)器正在瘋狂暴漲。敲下命令mpstat -P ALL 1查看每個 CPU 核心的實時分工真相瞬間令人哭笑不得全服務(wù)器除了CPU 0的軟中斷負載%soft死死定在 100% 滿負荷轉(zhuǎn)動外其余幾十個 CPU 核心全部都在悠閑地閑逛。這就是經(jīng)典的高并發(fā)網(wǎng)絡(luò)災(zāi)難——網(wǎng)卡中斷傾斜與“單核累死、眾核圍觀”。如果不深入網(wǎng)卡硬件控制器與內(nèi)核中斷分發(fā)鏈路把 RSS 多隊列與 CPU 軟中斷親和性Affinity徹底理順再頂級的千核服務(wù)器也會被一個被累癱的單核心活活卡死。一、網(wǎng)絡(luò)報文進入 CPU 的中斷路由拓撲要解決中斷傾斜必須弄清楚一個物理網(wǎng)卡數(shù)據(jù)包從網(wǎng)線到達 CPU經(jīng)歷了怎樣的硬件調(diào)度邏輯網(wǎng)線物理光電信號 │ ▼ [萬兆物理網(wǎng)卡 NIC] │ ├── 硬件 RSS 模塊: 對報文五元組執(zhí)行 Toeplitz 快速哈希 ▼ ┌─────────────────────────────────────────────────────────────┐ │ 網(wǎng)卡硬件多隊列 (Rx Queue 0 ~ Rx Queue N) │ ├──────────────┬──────────────┬──────────────┬────────────────┤ │ Queue 0 │ Queue 1 │ Queue 2 │ Queue N │ │ (觸發(fā) IRQ 121)│ (觸發(fā) IRQ 122)│ (觸發(fā) IRQ 123)│ (觸發(fā) IRQ 124) │ └──────────────┴──────────────┴──────────────┴────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ [未配置親和性時的內(nèi)核默認路由: 全部一股腦砸給 CPU 0 處理] ── 單核軟中斷被打爆現(xiàn)代網(wǎng)卡普遍支持RSSReceive Side Scaling接收端縮放技術(shù)。網(wǎng)卡硬件內(nèi)部集成了哈希計算單元根據(jù)數(shù)據(jù)包的“源 IP、目的 IP、源端口、目的端口、傳輸協(xié)議”五元組通過 Toeplitz 算法算出一個哈希值并將報文分散投遞進不同的硬件環(huán)形接收隊列Rx Queue。每一個硬件隊列擁有一個獨立的MSI-X 硬件中斷號IRQ。然而如果操作系統(tǒng)沒有精細化配置中斷親和性默認的irqbalance守護進程或者粗暴的內(nèi)核路由經(jīng)常會把所有隊列的中斷號全部綁在同一個 CPU 核心上導(dǎo)致無論你配備了多么先進的多隊列網(wǎng)卡所有的網(wǎng)絡(luò)軟中斷處理依然在單核獨木橋上艱難爬行。二、生產(chǎn)級硬核排查與多隊列調(diào)優(yōu)全鏈路把萬兆網(wǎng)卡的所有隊列均勻打散到所有 CPU 核心上必須經(jīng)過以下四步嚴密配置1. 檢查并拉滿網(wǎng)卡硬件隊列上限使用ethtool -l檢查網(wǎng)卡當前開啟的隊列數(shù)量是否與硬件支持的最大數(shù)量匹配# 查看硬件最大支持通道數(shù)與當前生效通道數(shù) ethtool -l eth0 # 輸出示例: # Channel parameters for eth0: # Pre-set maximums: # RX: 0 # TX: 0 # Combined: 32 -- 硬件最大支持 32 隊列 # Current hardware settings: # Combined: 4 -- 致命隱患: 默認竟然只開了 4 個隊列 # 立即將網(wǎng)絡(luò)通道數(shù)打滿至硬件上限 ethtool -L eth0 combined 322. 徹底停用添亂的 irqbalance 守護進程在追求極致低延遲的高性能服務(wù)器上Linux 自帶的irqbalance服務(wù)往往是個災(zāi)難。它經(jīng)常在各個核心之間胡亂遷移中斷號導(dǎo)致 CPU L1/L2 緩存行被頻繁沖刷Cache Invalidation。必須將其強制關(guān)閉轉(zhuǎn)為手工靜態(tài)綁定systemctl stop irqbalance systemctl disable irqbalance三、生產(chǎn)級自動化中斷親和性靜態(tài)綁定腳本以下是在生產(chǎn)服務(wù)器初始化時自動化提取網(wǎng)卡中斷號并與同一 NUMA 節(jié)點的 CPU 核心執(zhí)行一一綁定的工業(yè)級腳本#!/bin/bash INTERFACEeth0 # 1. 獲取網(wǎng)卡所在的物理 NUMA 節(jié)點 NUMA_NODE$(cat /sys/class/net/$INTERFACE/device/numa_node) if [ $NUMA_NODE -lt 0 ]; then NUMA_NODE0 fi # 2. 提取屬于該 NUMA 節(jié)點的專屬 CPU 核心列表 CPUS($(lscpu | grep NUMA node$NUMA_NODE CPU(s) | awk {print $4} | tr , )) echo [*] 網(wǎng)卡 $INTERFACE 掛載在 NUMA 節(jié)點 $NUMA_NODE分配綁定核心: ${CPUS[]} # 3. 提取網(wǎng)卡所有的 MSI-X 中斷號并按順序綁定至各 CPU IRQS($(grep $INTERFACE /proc/interrupts | awk -F: {print $1} | tr -d )) CPU_COUNT${#CPUS[]} INDEX0 for irq in ${IRQS[]}; do TARGET_CPU${CPUS[$((INDEX % CPU_COUNT))]} # 將中斷號綁定至指定 CPU 核心 (寫入 smp_affinity_list) echo $TARGET_CPU /proc/irq/$irq/smp_affinity_list echo [] 成功綁定中斷 IRQ $irq - CPU $TARGET_CPU INDEX$((INDEX 1)) done執(zhí)行完畢后每個網(wǎng)卡接收隊列的中斷處理被死死錨定在專屬的 CPU 核心上且與網(wǎng)卡物理插槽處于同一個 NUMA 內(nèi)存節(jié)點內(nèi)跨 Socket 遠程總線訪存開銷徹底歸零。四、生產(chǎn)壓測成效從單核暴斃到全核線速在 32 核物理服務(wù)器上使用發(fā)包機以 64 字節(jié)高頻網(wǎng)絡(luò)小包模擬 10 萬 QPS 突發(fā)流量對比中斷綁定前后的系統(tǒng)表現(xiàn)[網(wǎng)卡中斷親和性綁定前后生產(chǎn)壓測基準對比] 性能評估指標 綁定前狀態(tài) (默認配置) 完成 NUMA 親和綁定后 優(yōu)化改善幅度 整機網(wǎng)絡(luò)丟包率 (Drop) 14.8% (網(wǎng)卡劇烈丟包!) 0.00% (絕對零丟包) 網(wǎng)絡(luò)徹底穩(wěn)健 CPU 0 軟中斷 (%soft) 100% (單核暴斃卡死) 14.2% (平穩(wěn)輕量) 徹底解套 全核軟中斷負載分布 嚴重畸形 (1核忙,31核閑) 各核心完全均衡 (12%~15%) 完美負載均衡 單機最大穩(wěn)定轉(zhuǎn)發(fā) QPS 28,500 QPS 186,000 QPS 吞吐狂飆 6.5 倍 P999 響應(yīng)延遲 245 ms (嚴重積壓) 2.1 ms 長尾毛刺歸零數(shù)據(jù)給出了極其震撼的性能躍遷綁定前單核被打滿導(dǎo)致網(wǎng)卡緩沖區(qū)迅速溢出14.8% 的請求直接在網(wǎng)絡(luò)入口被強行丟棄綁定后32 個中斷號均勻落在 32 個 CPU 核心上原本累癱的 CPU 0 負載驟降至 14%整機吞吐直接暴漲6.5 倍單機承載能力飆升至接近 19 萬 QPS丟包率瞬間清零。五、高性能網(wǎng)絡(luò)老兵的親和性避坑守則在實施網(wǎng)卡與 CPU 綁定工程時切記守住以下兩條紅線絕對不要跨越物理 NUMA 節(jié)點綁定在雙路 CPUSocket 0 與 Socket 1服務(wù)器上如果網(wǎng)卡插在 Socket 0 的 PCIe 插槽中卻把中斷綁定到 Socket 1 的 CPU 核心上每次網(wǎng)卡 DMA 讀寫都必須跨越主板 QPI/UPI 互聯(lián)總線延遲會直接翻倍必須使用cat /sys/class/net/dev/device/numa_node嚴格確保同源綁定低端單隊列網(wǎng)卡開啟 RPS/RFS 兜底如果某些老舊服務(wù)器的網(wǎng)卡硬件只支持 1 個或 2 個隊列單純改中斷號無濟于事。此時必須在操作系統(tǒng)層面開啟RPSReceive Packet Steering由內(nèi)核軟件將單隊列的數(shù)據(jù)包通過計算哈希分發(fā)給其他 CPU 核心以軟件開銷換取多核算力均衡。