昨天週五臨下班了,心想加了一週班,今天如果不出意外的話...咳咳,不能說不能說(flag不能亂立),測試人員說系統很卡,然後去找運維,運維說機器cpu直接拉滿,我方了,因爲最後他測的功能是我寫的,果然準時下班是不存在的,登上服務器,因爲在docker裏面,所以這java進程無疑就是我們的的項目,證據確鑿
然後火速排查解決,原因是一個參數傳漏了,導致一張幾十萬的表join另一張幾十萬的表全查,boom...敲
今天分享一下排查思路。
假如生產出現CPU佔用過高,談談分析思路和問題定位?(結合linux命令和jdk命令)
[0].我們先模擬出一個生產CPU高佔用的問題,將其放在服務器上運行
javac -d . ProduceProblemPosition.java
java com.w4xj.problemposition.ProduceProblemPosition
java代碼如下,這裏只是寫一個簡單的示例
package com.w4xj.problemposition
import java.util.Random;
import java.util.UUID;
/**
* @Author by w4xj
* @Classname ProduceProblemPosition
* @Description 模擬生產問題定位
* @Date
* @Created by IDEA
*/
public class ProduceProblemPosition {
public static void main(String[] args) {
while(true){
System.out.println(UUID.randomUUID().toString().substring(0,8) + " *^_^* " + new Random().nextInt(99999));
}
}
}
[1].先用top命令找出CPU佔用最高的程序,得知其是一個java程序,並知道其pid
[2].ps -ef 或者 jps進一步定位,得知是一個怎樣後臺程序佔用CPU
[3].定位到具體線程或者代碼
①.ps -mp 進程 -o THREAD,tid,time
②.參數
-m 顯示所有的線程
-p pid進程使用cpu的時間
-o 用戶自定義輸出格式
[4].將需要的線程id轉換爲16進制格式(英文小寫格式)
2376 -> 948
方式①.printf "%x\n" 2376
方式②.計算器
[5].jstack 進程id | grep tid(16進制小寫英文) -A60
①.找到本公司的包名的類,定位到java類的行數
②.查看源文件
另外分享一些常用的服務器排查命令
1.生產服務器變慢,診斷思路和不同的緯度
[1].整機:top
①.load average:系統負載,三個數值若平均值大於60%,則表示系統壓力過大
②.精簡版:uptime
[2].CPU:vmstat
①.查看cpu(包含但不限於),vmstat -n 2 4表示每2秒採樣一次,共採樣4次
②.詳解
i.vmstat -n x y:表示採樣間隔x(單位:秒),總計採樣y次
ii.-procs
r:運行和等待CPU時間片的進程數,原則上1核CPU的運行隊列不要超過2,整個系統的運行隊列不能超過總核數的2倍,否則代表壓力過大
b:等待資源的進程數,比如正在等待磁盤I/O、網絡I/O等
iii.-cpu
us:用戶進程消耗CPU時間比,us值高,用戶進程消耗CPU時間多,如果長期大於50%,優化程序
sy:內核進程消耗的CPU時間百分比
us + sy參考值爲80%,如果us + sy大於80%,說明可能存在CPU不足
id:處於空閒的CPU百分比
wa:系統等待IO的CPU時間百分比
st:從虛擬機中偷走的百分比(如果正在使用虛擬機話,有此列,虛擬機想運行但是系統管理程序轉而運行其的對象的時間,如果虛擬機不希望運行任何對象,但是系統管理員運行了其他對象,這不算被偷走的cpu時間)
iv.-memory
swpd:虛擬內存已使用的大小,如果大於0,表示你的機器物理內存不足了,如果不是程序內存泄露的原因,那麼你該升級內存了或者把耗內存的任務遷移到其他機器。
free:空閒的物理內存的大小,我的機器內存總共8G,剩餘3415M。
buff:Linux/Unix系統是用來存儲,目錄裏面有什麼內容,權限等的緩存,我本機大概佔用300多M
cache cache:直接用來記憶我們打開的文件,給文件做緩衝,我本機大概佔用300多M(這裏是Linux/Unix的聰明之處,把空閒的物理內存的一部分拿來做文件和目錄的緩存,是爲了提高 程序執行的性能,當程序使用內存時,buffer/cached會很快地被使用。)
v.-swap
si:每秒從磁盤讀入虛擬內存的大小,如果這個值大於0,表示物理內存不夠用或者內存泄露了,要查找耗內存進程解決掉。我的機器內存充裕,一切正常。
so:每秒虛擬內存寫入磁盤的大小,如果這個值大於0,同上。
vi.-io
bi:塊設備每秒接收的塊數量,這裏的塊設備是指系統上所有的磁盤和其他塊設備,默認塊大小是1024byte,我本機上沒什麼IO操作,所以一直是0,但是我曾在處理拷貝大量數據(2-3T)的機器上看過可以達到140000/s,磁盤寫入速度差不多140M每秒
bo:塊設備每秒發送的塊數量,例如我們讀取文件,bo就要大於0。bi和bo一般都要接近0,不然就是IO過於頻繁,需要調整。
vii.-system
in:每秒CPU的中斷次數,包括時間中斷
cs:每秒上下文切換次數,例如我們調用系統函數,就要進行上下文切換,線程的切換,也要進程上下文切換,這個值要越小越好,太大了,要考慮調低線程或者進程的數目,例如在apache和nginx這種web服務器中,我們一般做性能測試時會進行幾千併發甚至幾萬併發的測試,選擇web服務器的進程可以由進程或者線程的峯值一直下調,壓測,直到cs到一個比較小的值,這個進程和線程數就是比較合適的值了。系統調用也是,每次調用系統函數,我們的代碼就會進入內核空間,導致上下文切換,這個是很耗資源,也要儘量避免頻繁調用系統函數。上下文切換次數過多表示你的CPU大部分浪費在上下文切換,導致CPU幹正經事的時間少了,CPU沒有充分利用,是不可取的。
③.額外查看
i.mpstat -P ALL 2:查看所有cpu核信息
pidstat [ 選項 ] [ <時間間隔> ] [ <次數> ]
-u:默認的參數,顯示各個進程的cpu使用統計
-r:顯示各個進程的內存使用統計
-d:顯示各個進程的IO使用情況
-p:指定進程號
-w:顯示每個進程的上下文切換情況
-t:顯示選擇任務的線程的統計信息外的額外信息
-T { TASK | CHILD | ALL }
這個選項指定了pidstat監控的。TASK表示報告獨立的task,CHILD關鍵字表示報告進程下所有線程統計信息。ALL表示報告獨立的task和task下面的所有線程。
注意:task和子線程的全局的統計信息和pidstat選項無關。這些統計信息不會對應到當前的統計間隔,這些統計信息只有在子線程kill或者完成的時候纔會被收集。
-V:版本號
-h:在一行上顯示了所有活動,這樣其他程序可以容易解析。
-I:在SMP環境,表示任務的CPU使用率/內核數量
-l:顯示命令名和所有參數
ii.pidstat -u 1 -p 進程編號:查看單個進程使用cpu的用量分解信息
pidstat [ 選項 ] [ <時間間隔> ] [ <次數> ]
-u:默認的參數,顯示各個進程的cpu使用統計
-r:顯示各個進程的內存使用統計
-d:顯示各個進程的IO使用情況
-p:指定進程號
-w:顯示每個進程的上下文切換情況
-t:顯示選擇任務的線程的統計信息外的額外信息
-T { TASK | CHILD | ALL }
這個選項指定了pidstat監控的。TASK表示報告獨立的task,CHILD關鍵字表示報告進程下所有線程統計信息。ALL表示報告獨立的task和task下面的所有線程。
注意:task和子線程的全局的統計信息和pidstat選項無關。這些統計信息不會對應到當前的統計間隔,這些統計信息只有在子線程kill或者完成的時候纔會被收集。
-V:版本號
-h:在一行上顯示了所有活動,這樣其他程序可以容易解析。
-I:在SMP環境,表示任務的CPU使用率/內核數量
-l:顯示命令名和所有參數
[3].內存:free
①.默認以kb爲單位,可通過參數來調節單位
-b (B), -k (KB), -m (MB), -g (GB) and –tera (TB)
②.經驗:
i.應用程序可用內存/系統物理內存>70%內存充足
ii.應用程序可用內存/系統物理內存<20%內存不足,需要增加內存
iii.20%-70%內存基本夠用
③.相關:pidstat -p 進程號 -r 間隔描述
[4].硬盤:df
df -h:查看磁盤剩餘空間數
[5].磁盤IO:iostat
①.命令iostat [ 選項 ] [ <時間間隔> [ <次數> ]]
②.常用參數
-c:只顯示系統CPU統計信息,即單獨輸出avg-cpu結果,不包括device結果
-d:單獨輸出Device結果,不包括cpu結果
-k/-m:輸出結果以kB/mB爲單位,而不是以扇區數爲單位
-x:輸出更詳細的io設備統計信息
interval/count:每次輸出間隔時間,count表示輸出次數,不帶count表示循環輸出
說明:更多選項使用使用man iostat查看
③.iostat 從系統開機到當前執行時刻的統計信息
輸出含義:
avg-cpu: 總體cpu使用情況統計信息,對於多核cpu,這裏爲所有cpu的平均值。重點關注iowait值,表示CPU用於等待io請求的完成時間。
Device: 各磁盤設備的IO統計信息。各列含義如下:
Device: 以sdX形式顯示的設備名稱
tps: 每秒進程下發的IO讀、寫請求數量
KB_read/s: 每秒從驅動器讀入的數據量,單位爲K。
KB_wrtn/s: 每秒從驅動器寫入的數據量,單位爲K。
KB_read: 讀入數據總量,單位爲K。
KB_wrtn: 寫入數據總量,單位爲K。
④.iostat -xdk 2 3 每隔2S輸出磁盤IO的詳細詳細,總共採樣3次
以上各列的含義如下:
rrqm/s: 每秒對該設備的讀請求被合併次數,文件系統會對讀取同塊(block)的請求進行合併
wrqm/s: 每秒對該設備的寫請求被合併次數
r/s: 每秒完成的讀次數
w/s: 每秒完成的寫次數
rkB/s: 每秒讀數據量(kB爲單位)
wkB/s: 每秒寫數據量(kB爲單位)
avgrq-sz:平均每次IO操作的數據量(扇區數爲單位)
avgqu-sz: 平均等待處理的IO請求隊列長度
await: 平均每次IO請求等待時間(包括等待時間和處理時間,毫秒爲單位)
svctm: 平均每次IO請求的處理時間(毫秒爲單位)
%util: 週期內用於IO操作的時間比率,即IO隊列非空的時間比率,若接近100%說明磁盤帶寬跑滿,需要優化程序或者增加磁盤
⑤.重點關注參數
iowait% 表示CPU等待IO時間佔整個CPU週期的百分比,如果iowait值超過50%,或者明顯大於%system、%user以及%idle,表示IO可能存在問題。
avgqu-sz 表示磁盤IO隊列長度,即IO等待個數。若長期大隊列,也說明IO新能不佳
rkB/s、wkB/s、r/s、w/s若這些值一直處於很高,說明程序一直處於高IO狀態,需要排查分析是否程序需要優化
await若和svctm越接近,表示磁盤IO性能好,反之,若await遠大於svctm則說明IO隊列等待時間過長,需要優化程序或者更換磁盤
%util 表示磁盤忙碌情況,一般該值超過80%表示該磁盤可能處於繁忙狀態。
⑥.相關:pidstat -d 採樣間隔秒數 -p 進程號
[6].網絡IO:ifstat
①.若本地需要安裝
wget http://distfiles.macports.org/ifstat/ifstat-1.1.tar.gz
tar xzvf ifstat-1.1.tar.gz
cd ifstat-1.1
./configure
make
make install
②.命令,ifstat,注意要用安裝的ifstat
③.參數:
-l 監測環路網絡接口。缺省情況下ifstat監測活動的所有非環路網絡接口
-a 監測能檢測到的所有網絡接口的狀態信息。
-z 隱藏流量是無的接口,如接口啓動了但是未使用的。
-i <interface> 指定要監測的接口。
-s 通過SNMP查詢一個遠程主機。
-h 顯示幫助信息
-n 關閉週期性顯示頭部信息。
-t 在每一行的開頭加一個時間戳
-T 報告所有檢測接口的全部帶寬
-w 指定間隔時間(與官方的文檔說明並不同,不知道是不是寫文檔的人寫錯,反正我測試後是間隔時間)
-W 如果顯示內容超出終端窗口的寬度,就換行
-S 在同一行更新顯示內容
-b 用kbits/s顯示帶寬
-q 按鍵模式
-v 顯示版本信息
-d 指定一個驅動來收集狀態信息