性能分析(5)- 軟中斷導致 CPU 使用率過高的案例
- 2020 年 8 月 11 日
- 筆記
- 測試高級進階技能系列 - 性能分析, 性能分析
性能分析小案例系列,可以通過下面鏈接查看哦
//www.cnblogs.com/poloyy/category/1814570.html
前言
軟中斷基本原理,可參考這篇部落格://www.cnblogs.com/poloyy/p/13435519.html
中斷
- 一種非同步的事件處理機制,用來提供系統的並發處理能力
- 當中斷事件發生,會觸發執行中斷處理程式
- 中斷處理程式分為上半部和下半部
- 上半部:硬中斷,快速處理中斷
- 下半部:軟中斷,用來非同步處理上半部未完成的工作
軟中斷
- 每個 CPU 都對應一個軟中斷內核執行緒,名字是 ksoftirqd/CPU 編號
- 當軟中斷事件的頻率過高時,內核執行緒也會因為 CPU 使用率過高而導致軟中斷處理不及時,進而引發網路收發延遲,調度緩慢等性能問題
軟中斷頻率過高案例
系統配置
Ubuntu 18.04, 2 CPU,2GB 記憶體,共兩台虛擬機
三個工具
- sar:是一個系統活動報告工具,既可以實時查看系統的當前活動,又可以配置保存和報告 歷史統計數據。
- hping3:是一個可以構造 TCP/IP 協議數據包的工具,可以對系統進行安全審計、防火牆 測試等。
- tcpdump:是一個常用的網路抓包工具,常用來分析各種網路問題
虛擬機關係

通過 docker 運行案例
在 VM1 中執行命令
docker run -itd --name=nginx -p 80:80 nginx
通過 curl 確認 Nginx 正常啟動
在 VM2 中執行命令
curl http://172.20.72.58/
通過 hping3 模擬 Nginx 的客戶端請求
在 VM2 中執行命令
hping3 -S -p 80 -i u100 172.20.72.58
- -S:參數表示設置 TCP 協議的 SYN(同步序列號)
- -p:表示目的埠為 80
- -i:u100 表示每隔 100 微秒發送一個網路幀
回到 VM1
感覺系統響應明顯變慢了,即便只 是在終端中敲幾個回車,都得很久才能得到響應
分析系統為什麼會響應變慢
以下命令均在 VM1 中執行
通過 top 命令查看系統資源使用情況

- 系統 CPU 使用率(用戶態 us 和內核態 sy )並不高
- 平均負載適中,只有 2 個 R 狀態的進程,無殭屍進程
- 但是軟中斷進程1號(ksoftirqd/1)的 CPU 使用率偏高,而且處理軟中斷的 CPU 佔比已達到 94
- 此外,並無其他異常進程
- 可以猜測,軟中斷就是罪魁禍首
確認是什麼類型的軟中斷
觀察 /proc/softirqs 文件的內容,就能知道各種軟中斷類型的次數
這裡的各類軟中斷次數,又是什麼時間段里的次數呢?
- 它是系統運行以來的累積中斷次數
- 所以直接查看文件內容,得到的只是累積中斷次數,對這裡的問題並沒有直接參考意義
- 中斷次數的變化速率才是我們需要關注的
通過 watch 動態查看命令輸出結果
因為我的機器是兩核,如果直接讀取 /proc/softirqs 會列印 128 核的資訊,但對於我來說,只要看前面兩核的資訊足以,所以需要寫提取關鍵數據
watch -d "/bin/cat /proc/softirqs | /usr/bin/awk 'NR == 1{printf \"%-15s %-15s %-15s\n\",\" \",\$1,\$2}; NR > 1{printf \"%-15s %-15s %-15s\n\",\$1,\$2,\$3}'"

結果分析
- TIMER(定時中斷)、 NET_RX(網路接收)、SCHED(內核調度)、RCU(RCU 鎖)等這幾個軟中斷都在不停變化
- 而 NET_RX,就是網路數據包接收軟中斷的變化速率最快
- 其他幾種類型的軟中斷,是保證 Linux 調度、時鐘、臨界區保護這些正常工作所必需的,所以有變化時正常的
通過 sar 查看系統的網路收發情況
上面確認了從網路接收的軟中斷入手,所以第一步應該要看下系統的網路接收情況
sar 的好處
- 不僅可以觀察網路收發的吞吐量(BPS,每秒收發的位元組數)
- 還可以觀察網路收發的 PPS(每秒收發的網路幀數)
執行 sar 命令
sar -n DEV 1

- 第二列:IFACE 表示網卡
- 第三、四列:rxpck/s 和 txpck/s 分別表示每秒接收、發送的網路幀數【PPS】
- 第五、六列:rxkB/s 和 txkB/s 分別表示每秒接收、發送的千位元組數【BPS】
結果分析
對網卡 ens33 來說
- 每秒接收的網路幀數比較大,幾乎達到 8w,而發送的網路幀數較小,只有接近 4w
- 每秒接收的千位元組數只有 4611 KB,發送的千位元組數更小,只有2314 KB
docker0 和 veth04076e3
- 數據跟 ens33 基本一致只是發送和接收相反,發送的數據較大而接收的數據較小
- 這是 Linux 內部網橋轉發導致的,暫且不用深究,只要知道這是系統把 ens33 收到的包轉發給 Nginx 服務即可
異常點
- 前面說到是網路數據包接收軟中斷的問題,那就重點看 ens33
- 接收的 PPS 達到 8w,但接收的 BPS 只有 5k 不到,網路幀看起來是比較小的
- 4611 * 1024 / 78694 = 64 位元組,說明平均每個網路幀只有 60 位元組,這顯然是很小的網路幀,也就是常說的小包問題
靈魂拷問
如何知道這是一個什麼樣的網路幀,它又是從哪裡發過來的呢?
通過 tcpdump 抓取網路包
已知條件
Nginx 監聽在 80 埠, 它所提供的 HTTP 服務是基於 TCP 協議的
執行 tcpdump 命令
tcpdump -i ens33 -n tcp port 80
- -i ens33:只抓取 ens33 網卡
- -n:不解析協議名和主機名
- tcp port 80:表示只抓取 tcp 協議並且埠號為 80 的網路幀

172.20.72.59.52195 > 172.20.72.58.80
- 表示網路幀從 172.20.72.59 的 52195 埠發 送到 172.20.72.58 的 80 埠
- 也就是從運行 hping3 機器的 52195 埠發送網路幀, 目的為 Nginx 所在機器的 80 埠
Flags [S]
表示這是一個 SYN 包
性能分析結果
結合 sar 命令發現的 PPS 接近 4w 的現象,可以認為這就是從 172.20.72.59 這個地址發送過來的 SYN FLOOD 攻擊
解決 SYN FLOOD 問題
從交換機或者硬體防火牆中封掉來源 IP,這樣 SYN FLOOD 網路幀就不會發送到伺服器中
後續的期待
至於 SYN FLOOD 的原理和更多解決思路在後面會講到哦
分析的整體思路
- 系統出現卡頓,執行命令,響應也會變慢
- 通過 top 查看系統資源情況
- 發現 CPU 使用率(us 和 sy)均不高,平均負載適中,沒有超 CPU 核數的運行狀態的進程,也沒有殭屍進程
- 但是發現處理軟中斷的 CPU 佔比(si)較高,在進程列表也可以看到軟中斷進程 CPU 使用率偏高,猜測是軟中斷導致系統變卡頓的主要原因
- 通過 /proc/sorfirqs 查看軟中斷類型和變化頻率,發現直接 cat 的話會列印 128 個核的資訊,但只想要兩個核的資訊
- 所以結合 awk 進行過濾,再通過 watch 命令可以動態輸出查看結果
- 發現有多個軟中斷類型在變化,重點是 NET_RX 變化頻率超高,而且幅度也很大,它是網路數據包接收軟中斷,暫且認為它是問題根源
- 既然跟網路有關係,可以先通過 sar 命令查看系統網路接收和發送的整體情況
- 然後可以看到接收的 PPS 會比接收的 BPS 大很多,做下運算,發現網路幀會非常小,也就是常說的小包問題
- 接下來,通過 tcpdump 抓取 80埠的 tcp 協議網路包,會發現大量來自 VM2 發送的 SYN 包,結合 sar 命令,確認是 SYN FLOOD 攻擊
