中斷
中斷是一種異步的事件處理機制,用來提高系統的並發處理能力
中斷事件發生,會觸發執行中斷處理程序,而中斷處理程序被分為上半部和下半部這兩個部分
1.上半部對應硬中斷,用來快速處理中斷
2.下半部對應軟中斷,用來異步處理上半部未完成的工作
Linux中的軟中斷包括網絡收發、定時、調度、RCU 鎖等各種類型
可以查看proc文件系統中的/proc/softirqs觀察軟中斷的運行情況
在Linux中,每個CPU都對應一個軟中斷內核線程,名字是ksoftirqd/CPU編號
當軟中斷事件的頻率過高時,內核線程也會因為CPU使用率過高而導致軟中斷處理不及時,
進而引發網絡收發延遲、調度緩慢等性能問題
軟中斷CPU使用率過高也是一種最常見的性能問題
案例
實驗環境
# 服務端(192.168.1.6)
配置:2CPU,4G內存,centos7.6_64
預先安裝docker、tcpdump、sar等工具(yum install tcpdump、sar)
# 客戶端(192.168.1.5)
配置:1CPU,2G內存,centos7.6_64
# 預先安裝hping3工具
[root@local_deploy_192-168-1-5 ~]# yum install hping3 -y
工具介紹
sar 是一個系統活動報告工具,既可以實時查看系統的當前活動,又可以配置保存和報告歷史統計數據
hping3 是一個可以構造TCP/IP協議數據包的工具,可以對系統進行安全審計、防火牆測試等
tcpdump 是一個常用的網絡抓包工具,常用來分析各種網絡問題
1.本次實驗架構圖
其中一台虛擬機運行Nginx ,用來模擬待分析的Web服務器
另一台當作Web服務器的客戶端,用來給Nginx增加壓力請求
2.在服務端,啟動一個nginx應用
# 運行Nginx服務並對外開放80端口
[root@local_sa_192-168-1-6 ~]# docker run -itd --name=nginx -p 80:80 nginx
# 使用 curl 訪問Nginx監聽的端口,確認Nginx正常啟動
[root@local_sa_192-168-1-6 ~]# curl http://192.168.1.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
......
3.在客戶端,使用hping3,模擬對nginx的請求
# -S 參數表示設置TCP協議的SYN(同步序列號)
# -p 表示目的端口為80
# -i u100表示每隔100微秒發送一個網絡幀
# 注:如果你在實踐過程中現象不明顯,可以嘗試把100調小,比如調成10甚至1
[root@local_deploy_192-168-1-5 ~]# hping3 -S -p 80 -i u10 192.168.1.6
# hping3這是一個SYN FLOOD攻擊
# 此時查看服務器開始卡頓
4.在服務端,發現服務端開始卡頓,使用top命令查看
# top運行后按數字1切換到顯示所有CPU
[root@local_sa_192-168-1-6 ~]# top
top - 10:50:58 up 1 days, 22:10, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 122 total, 1 running, 71 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni, 96.7 id, 0.0 wa, 0.0 hi, 3.3 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni, 95.6 id, 0.0 wa, 0.0 hi, 4.4 si, 0.0 st
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 0 0 0 S 0.3 0.0 0:01.64 ksoftirqd/0
16 root 20 0 0 0 0 S 0.3 0.0 0:01.97 ksoftirqd/1
2663 root 20 0 923480 28292 13996 S 0.3 0.3 4:58.66 docker-containe
3699 root 20 0 0 0 0 I 0.3 0.0 0:00.13 kworker/u4:0
3708 root 20 0 44572 4176 3512 R 0.3 0.1 0:00.07 top
1 root 20 0 225384 9136 6724 S 0.0 0.1 0:23.25 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.03 kthreadd
...
# 輸出結果分析
平均負載全是0,就緒隊列里面只有一個進程(1 running)
每個CPU的使用率都挺低,最高的CPU1的使用率也只有4.4%,並不算高
再看進程列表,CPU使用率最高的進程也只有0.3%,還是不高呀
仔細看top的輸出,兩個CPU的使用率雖然分別只有3.3%和4.4%,但都用在了軟中斷上
而從進程列表上也可以看到,CPU使用率最高的也是軟中斷進程ksoftirqd
看起來,軟中斷有點可疑了
5.在服務端,查看中斷次數的變化速率
/proc/softirqs文件它是系統運行以來的累積中斷次數
直接查看文件內容,得到的只是累積中斷次數,對這里的問題並沒有直接參考意義
【中斷次數的變化速率】才是需要關注的
# watch 命令可以定期運行一個命令來查看輸出
# -d 以高亮出變化的部分
[root@local_sa_192-168-1-6 ~]# watch -d cat /proc/softirqs
CPU0 CPU1
HI: 0 0
TIMER: 1083906 2368646
NET_TX: 53 9
NET_RX: 1550643 1916776
BLOCK: 0 0
IRQ_POLL: 0 0
TASKLET: 333637 3930
SCHED: 963675 2293171
HRTIMER: 0 0
RCU: 1542111 1590625
# 通過/proc/softirqs文件內容的變化情況
發現TIMER(定時中斷)、NET_RX(網絡接收)、SCHED(內核調度)、RCU(RCU 鎖)等這幾個軟中斷都在不停變化
其中,NET_RX,也就是網絡數據包接收軟中斷的變化速率最快
而其他幾種類型的軟中斷,是保證Linux調度、時鍾和臨界區保護這些正常工作所必需的,所以它們有一定的變化倒是正常的
# 接下來,就從網絡接收的軟中斷着手,繼續分析
既然是網絡接收的軟中斷,第一步應該就是觀察系統的網絡接收情況,推薦使用sar工具
6.在服務端,使用sar工具分析
# sar 可以用來查看系統的網絡收發情況
# 不僅可以觀察網絡收發的吞吐量(BPS,每秒收發的字節數)
# 還可以觀察網絡收發的PPS,即每秒收發的網絡幀數
# -n DEV表示顯示網絡收發的報告,間隔1秒輸出一組數據
[root@local_sa_192-168-1-6 ~]# sar -n DEV 1
15:03:46 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcs
15:03:47 eth0 12607.00 6304.00 664.86 358.11 0.00 0.00 0
15:03:47 docker0 6302.00 12604.00 270.79 664.66 0.00 0.00 0
15:03:47 lo 0.00 0.00 0.00 0.00 0.00 0.00 0
15:03:47 veth9f6bbcd 6302.00 12604.00 356.95 664.66 0.00 0.00 0
# 輸出結果介紹
第一列:表示報告的時間
第二列:IFACE 表示網卡
第三、四列:rxpck/s和txpck/s分別表示每秒接收、發送的網絡幀數,也就是PPS
第五、六列:rxkB/s和txkB/s 分別表示每秒接收、發送的千字節數,也就是BPS
# 分析
對網卡eth0來說,每秒接收的網絡幀數比較大,達到了12607,而發送的網絡幀數則比較小,只有6304
每秒接收的千字節數只有664KB,而發送的千字節數更小,只有358KB
docker0和veth9f6bbcd的數據跟eth0基本一致,只是發送和接收相反,發送的數據較大而接收的數據較小
這是Linux內部網橋轉發導致的,是系統把eth0收到的包轉發給Nginx服務
從這些數據中分析
既然懷疑是網絡接收中斷的問題,重點來看eth0
接收的PPS比較大,達到12607,而接收的BPS卻很小,只有664KB
直觀來看網絡幀應該都是比較小的
稍微計算一下,664*1024/12607 = 54字節,
說明平均每個網絡幀只有54字節,這顯然是很小的網絡幀,也就是通常所說的小包問題
查看網絡幀從哪里發送過來的
7.在服務端,tcpdump工具抓包
# tcpdump抓取eth0上的包就可以了
# 已經知道,Nginx監聽在80端口,它所提供的HTTP服務是基於TCP協議的,
# 所以可以指定TCP協議和80端口精確抓包
# -i eth0只抓取eth0網卡
# -n 不解析協議名和主機名
# tcp port 80 表示只抓取tcp協議並且端口號為80的網絡幀
[root@local_sa_192-168-1-6 ~]# tcpdump -i eth0 -n tcp port 80
:34:27.439264 IP 192.168.1.5.51070 > 192.168.1.6.http: Flags [S], seq 2133566800, win 512, length 0
# 輸出結果分析
192.168.1.5.51070 > 192.168.1.6.http 表示網絡幀從192.168.1.5的51070端口發送到
192.168.1.6的80(http)端口
也就是從運行hping3機器的51070端口發送網絡幀,目的為Nginx所在機器的80端口
Flags[S]則表示這是一個SYN包
再加上前面用sar發現的,PPS超過12000的現象,
現在可以確認,這就是從192.168.1.5 這個地址發送過來的SYN FLOOD攻擊
8.最終分析
到這里,已經做了全套的性能診斷和分析
從系統的軟中斷使用率高這個現象出發
通過觀察/proc/softirqs文件的變化情況
判斷出軟中斷類型是網絡接收中斷
再通過sar和tcpdump,確認這是一個SYN FLOOD問題
SYN FLOOD問題最簡單的解決方法,就是從交換機或者硬件防火牆中封掉來源IP
這樣SYN FLOOD網絡幀就不會發送到服務器中
關於SYN FLOOD的原理和更多解決思路,可以關注后面的博客
小結
軟中斷CPU使用率(softirq)升高是一種很常見的性能問題
雖然軟中斷的類型很多
但實際生產中,遇到的性能瓶頸大多是網絡收發類型的軟中斷,特別是網絡接收的軟中斷
在碰到這類問題時,可以借用sar、tcpdump等工具,做進一步分析