上下文切換頻繁,導致load average 過高
一、問題現象
現網有兩臺虛擬機器主機95%的cpu處於idle狀態,記憶體使用率也不是特別高,而主機的load average達到了40多。
二、問題分析
先在主機上通過top、free、ps、iostat 等常用工具分析了下主機的CPU、記憶體、IO使用情況,發現三者都不高。通過vmstat 1 檢視的結果如下:
從vmstat的輸出結果來看,io項的block in 和block out 並不頻繁。而system項的每稱的中斷數(in)、每秒的上下文切換(cs)特別頻繁。這就造成load avaerage會特別高。大方向上的根因找到了,具體是哪個程序如何頻繁的進行中斷和上下檔案的切換呢?
這裡使用pidstat -w 1 (每秒重新整理輸出上下文切換情況),輸出見下圖:
從上圖中可以看到有cswch(自願的上下文切換)和nvcswch(非自願的上下文切換)及對應的命令, 出vsftpd佔用的檔案交換比較多。可以看到這裡顯示的cs 值和總值還是有比較大的差距,由於主機上啟動了不止一個vsftpd程序,而且pidstat 通過1秒重新整理的時候並不會顯示所有,通過pidstat -w執行幾次收集所有發現所有的vsftpd程序佔用的cs值疊加和vmstat裡的比較相近了。
將結果通知業務人員後,和業務人員的猜測也一致,由於ftp使用的目錄結構層次較深、檔案數也比較多,業務在備份老的使用目錄並重新建立單層目錄後,觀察一段後,發現load average降下來了,穩定在1以下。
當然這裡只是處理方法的一種,現網中有些程式不好進行這樣的修改的,又不讓讓程序在cpu之間頻繁切換的,也有通過設定固定執行的CPU上進行調優的方法,如下兩個程序執行在0-7號cpu上:
- [[email protected] ~]# taskset -c -p 6389
- pid 6389's current affinity list: 0-7
- [[email protected] ~]# taskset -c -p 6580
- pid 6580's current affinity list:0-7
可以通過taskset讓其固定在0-1號cpu上執行:
- [[email protected]
這樣做的原理是每當程序在切換到下一個cpu core上進會flush當前的cache資料,指定CPU時會減少這樣的操作,增加程序的處理速度。這個對老的程式調優時比較有效。
三、有關上下文切換
1、上下文切換的理解
什麼是上下檔案切換呢?引用老外的一句話:A context switch (also sometimes referred to as a process switch or a task switch) is the switching of the CPU (central processing unit) from one process or thread to another.更詳細的說明可以參看linfo站點 或 維基百科 。
context switch過高會導致CPU像個搬運工,頻繁在暫存器和執行佇列之間奔波 ,更多的時間花在了執行緒切換,而不是真正工作的執行緒上。直接的消耗包括CPU暫存器需要儲存和載入,系統排程器的程式碼需要執行。間接消耗在於多核cache之間的共享資料。
2、引起上下文切換的原因
對於搶佔式作業系統而言, 大體有幾種:
- 當前任務的時間片用完之後,系統CPU正常排程下一個任務;
- 當前任務碰到IO阻塞,排程執行緒將掛起此任務,繼續下一個任務;
- 多個任務搶佔鎖資源,當前任務沒有搶到,被排程器掛起,繼續下一個任務;
- 使用者程式碼掛起當前任務,讓出CPU時間;
- 硬體中斷;
什麼樣的操作會引起CS,這裡有一篇博文感覺寫的很不錯,雖然其中的程式碼部分並不是理解 。其中有如下幾句話:
linux中一個程序的時間片到期,或是有更高優先順序的程序搶佔時,是會發生CS的,但這些都是我們應用開發者不可控的 ---前面一部分描述的很到位,後面一部分在系統層面和kernel 開發層面可以呼叫nice 或 renice進行設定優先順序以保證某些程式優先在CPU中的佔用時間,但也不能細化到CS層面。
站在開發者的角度,我們的程序可以主動地向核心申請進行CS 。操作方法為:休眠當前程序/執行緒;喚醒其他程序/執行緒 。
3、上下文切換測試工具
1、LMbench 是頻寬(讀取快取檔案、記憶體拷貝、讀寫記憶體、管道等)和反應時間(上下文切換、網路、程序建立等)的評測工具;
2、micro-benchmark contextswitch 可以測試不同的CPU在最少多少ns可以進行一次上下檔案切換,再轉化為秒,我們可以確認該處理器每可以進行的上下檔案切換數 ,該工具的使用可以參看tsuna的blog。
4、上下文切換的檢視方法
sar -w ,這個只是能看出主機上總的上下檔案切換的情況
- # sar -w 1
- proc/s
- Total number of tasks created per second.
- cswch/s
- Total number of context switches per second.
同樣,vmstat也可以檢視總的上下文切換情況,不過vmstart輸出的結果更多,便比通過對比發現問題:
- # vmstat 3
- procs -----------memory-------------swap-------io-----system------cpu----
- r b swpd free buff cache si so bi bo in cs us sy id wa
- 207292249472823402291972000000713790
- 007292251808823442291968000184242009011990
- 00729225187682344229196800083172015710990
- 00729225187682344229196800073122011610990
檢視每個程序或執行緒的上下檔案使用情況,可以使用pidstat命令或者通過檢視proc 。
- # pidstat -w 每個程序的context switching情況
- # pidstat -wt 細分到每個threads
- 檢視proc下的檔案方法如下:
- # pid=307
- # grep ctxt /proc/$pid/status
- voluntary_ctxt_switches:41#自願的上下文切換
- nonvoluntary_ctxt_switches:16#非自願的上下文切換
cswch/s: 每秒任務主動(自願的)切換上下文的次數,當某一任務處於阻塞等待時,將主動讓出自己的CPU資源。
nvcswch/s: 每秒任務被動(不自願的)切換上下文的次數,CPU分配給某一任務的時間片已經用完,因此將強迫該程序讓出CPU的執行權。
上下文切換部分零零碎碎先到這裡吧,只是想說明上下文切換還是比較重要的一個指標的。nagios check_mk預設有對上下文的監控,其使用的方法是通過兩/proc/stat檔案裡取到ctxt行,並取兩個時間段之間的差值來確認。
- # cat /proc/stat|grep ctxt
- ctxt 111751207