日常的工做中,在衡量服務器的性能時,常常會涉及到幾個指標,load、cpu、mem、qps、rt等。每一個指標都有其獨特的意義,不少時候在線上出現問題時,每每會伴隨着某些指標的異常。大部分狀況下,在問題發生以前,某些指標就會提早有異常顯示。java
對於這些指標的理解和查看、異常解決等,是程序員們重要的必備技能。本文,主要來介紹一下一個比較重要的指標——機器負載(Load),主要涉及負載的定義、查看負載方式、負載飆高排查思路等。linux
負載(load)是linux機器的一個重要指標,直觀了反應了機器當前的狀態。程序員
來看下負載的定義是怎樣的:數據庫
In UNIX computing, the system load is a measure of the amount of computational work that a computer system performs. The load average represents the average system load over a period of time. It conventionally appears in the form of three numbers which represent the system load during the last one-, five-, and fifteen-minute periods.(wikipedia)api
簡單解釋一下:在UNIX系統中,系統負載是對當前CPU工做量的度量,被定義爲特定時間間隔內運行隊列中的平均線程數。load average 表示機器一段時間內的平均load。這個值越低越好。負載太高會致使機器沒法處理其餘請求及操做,甚至致使死機。安全
Linux的負載高,主要是因爲CPU使用、內存使用、IO消耗三部分構成。任意一項使用過多,都將致使服務器負載的急劇攀升。服務器
在Linux機器上,有多個命令均可以查看機器的負載信息。其中包括uptime
、top
、w
等。app
uptime
命令uptime
命令可以打印系統總共運行了多長時間和系統的平均負載。uptime命令能夠顯示的信息顯示依次爲:如今時間、系統已經運行了多長時間、目前有多少登錄用戶、系統在過去的1分鐘、5分鐘和15分鐘內的平均負載。ide
➜ ~ uptime 13:29 up 23:41, 3 users, load averages: 1.74 1.87 1.97
這行信息的後半部分,顯示」load average」,它的意思是」系統的平均負荷」,裏面有三個數字,咱們能夠從中判斷系統負荷是大仍是小。工具
1.74 1.87 1.97
這三個數字的意思分別是1分鐘、5分鐘、15分鐘內系統的平均負荷。咱們通常表示爲load一、load五、load15。
w
命令w命令的主要功能實際上是顯示目前登入系統的用戶信息。可是與who不一樣的是,w命令功能更增強大,w命令還能夠顯示:當前時間,系統啓動到如今的時間,登陸用戶的數目,系統在最近1分鐘、5分鐘和15分鐘的平均負載。而後是每一個用戶的各項數據,項目顯示順序以下:登陸賬號、終端名稱、遠 程主機名、登陸時間、空閒時間、JCPU、PCPU、當前正在運行進程的命令行。
➜ ~ w 14:08 up 23:41, 3 users, load averages: 1.74 1.87 1.97 USER TTY FROM LOGIN@ IDLE WHAT hollis console - 六14 23:40 - hollis s000 - 六14 20:24 -zsh hollis s001 - 六15 - w
從上面的w
命令的結果能夠看到,當前系統時間是14:08,系統啓動到如今經歷了23小時41分鐘,共有3個用戶登陸。系統在近1分鐘、5分鐘和15分鐘的平均負載分別是1.74 1.87 1.97
。這和uptime
獲得的結果相同。 下面還打印了一些登陸的用戶的各項數據,不詳細介紹了。
top
命令top命令是Linux下經常使用的性能分析工具,可以實時顯示系統中各個進程的資源佔用情況,相似於Windows的任務管理器。
➜ ~ top Processes: 244 total, 3 running, 9 stuck, 232 sleeping, 1484 threads 14:16:01 Load Avg: 1.74, 1.87, 1.97 CPU usage: 8.0% user, 6.79% sys, 85.19% idle SharedLibs: 116M resident, 16M data, 14M linkedit. MemRegions: 66523 total, 2152M resident, 50M private, 930M shared. PhysMem: 7819M used (1692M wired), 370M unused. VM: 682G vsize, 533M framework vsize, 6402060(0) swapins, 7234356(0) swapouts. Networks: packets: 383006/251M in, 334448/60M out. Disks: 1057821/38G read, 350852/40G written. PID COMMAND %CPU TIME #TH #WQ #PORT MEM PURG CMPRS PGRP PPID STATE BOOSTS %CPU_ME %CPU_OTHRS UID FAULTS COW MSGSENT MSGRECV SYSBSD SYSMACH CSW 30845 top 3.0 00:00.49 1/1 0 21 3632K 0B 0B 30845 1394 running *0[1] 0.00000 0.00000 0 3283+ 112 203556+ 101770+ 8212+ 119901+ 823+ 30842 Google Chrom 0.0 00:47.39 17 0 155 130M 0B 0B 1146 1146 sleeping *0[1] 0.00000 0.00000 501 173746 2697 117678 37821 364228 444830 310043
上面的輸出結果中,Load Avg: 1.74, 1.87, 1.97顯示的就是負載信息。
對於機器的Load到底多少算正常的問題,一直都是頗有爭議的,不一樣人有着不一樣的理解。對於單個CPU,有人認爲若是Load超過0.7就算是超出正常範圍了。也有人認爲只要不超過1都沒問題。也有人認爲,單個CPU的負載在2如下均可以接受。
爲何會有這麼多不一樣的理解呢,是由於不一樣的機器除了CPU影響以外還有其餘因素的影響,運行的程序、機器內存、甚至是機房溫度等都有可能有區別。
好比,有些機器用於定時執行大量的跑批任務,這個時間段內,Load可能會飆的比較高。而其餘時間可能會比較低。那麼這段飆高時間咱們要不要去排查問題呢?
個人建議是,最好根據本身機器的實際狀況,創建一個指標的基線(如近一個月的平均值),只要平常的load在基線上下範圍內不太大均可以接收,若是差距太多可能就要人爲介入檢查了。
可是,總要有個建議的閾值吧,關於這個值。阮一峯在本身的博客中有過如下建議:
當系統負荷持續大於0.7,你必須開始調查了,問題出在哪裏,防止狀況惡化。
當系統負荷持續大於1.0,你必須動手尋找解決辦法,把這個值降下來。
當系統負荷達到5.0,就代表你的系統有很嚴重的問題,長時間沒有響應,或者接近死機了。你不該該讓系統達到這個值。
以上指標都是基於單CPU的,可是如今不少電腦都是多核的。因此,對通常的系統來講,是根據cpu數量去判斷系統是否已通過載(Over Load)的。若是咱們認爲0.7算是單核機器負載的安全線的話,那麼四核機器的負載最好保持在3(4*0.7 = 2.8)如下。
還有一點須要提一下,在Load Avg的指標中,有三個值,1分鐘系統負荷、5分鐘系統負荷,15分鐘系統負荷。咱們在排查問題的時候也是能夠參考這三個值的。
通常狀況下,1分鐘系統負荷表示最近的暫時現象。15分鐘系統負荷表示是持續現象,並不是暫時問題。若是load15較高,而load1較低,能夠認爲狀況有所好轉。反之,狀況可能在惡化。
致使負載高的緣由可能很複雜,有多是硬件問題也多是軟件問題。
若是是硬件問題,那麼說明機器性能確實就不行了,那麼解決起來很簡單,直接換機器就能夠了。
前面咱們提過,CPU使用、內存使用、IO消耗均可能致使負載高。若是是軟件問題,有可能因爲Java中的某些線程被長時間佔用、大量內存持續佔用等致使。建議從如下幾個方面排查代碼問題:
一、是否有內存泄露致使頻繁GC 二、是否有死鎖發生 三、是否有大字段的讀寫 四、會不會是數據庫操做致使的,排查SQL語句問題。
這裏還有個建議,若是發現線上機器Load飆高,能夠考慮先把堆棧內存dump下來後,進行重啓,暫時解決問題,而後再考慮回滾和排查問題。
一、使用uptime查看當前load,發現load飆高。
➜ ~ uptime 13:29 up 23:41, 3 users, load averages: 10 10 10
二、使用top命令,查看佔用CPU較高的進程ID。
➜ ~ top PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1893 admin 20 0 7127m 2.6g 38m S 181.7 32.6 10:20.26 java
發現PID爲1893的進程佔用CPU 181%。並且是一個Java進程,基本判定是軟件問題。
三、使用 top
命令,查看具體是哪一個線程佔用率較高
➜ ~ top -Hp 1893 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4519 admin 20 0 7127m 2.6g 38m R 18.6 32.6 0:40.11 java
四、使用printf
命令查看這個線程的16進制
➜ ~ printf %x 4519 11a7
五、使用jstack
命令查看當前線程正在執行的方法。(Java命令學習系列(二)——Jstack)
➜ ~ jstack 1893 |grep -A 200 11a7 "thread-5" #500 daemon prio=10 os_prio=0 tid=0x00007f632314a800 nid=0x11a2 runnable [0x000000005442a000] java.lang.Thread.State: RUNNABLE at sun.misc.URLClassPath$Loader.findResource(URLClassPath.java:684) at sun.misc.URLClassPath.findResource(URLClassPath.java:188) at java.net.URLClassLoader$2.run(URLClassLoader.java:569) at java.net.URLClassLoader$2.run(URLClassLoader.java:567) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findResource(URLClassLoader.java:566) at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248) at com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)
從上面的線程的棧日誌中,能夠發現,當前佔用CPU較高的線程正在執行我代碼的com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)類。那麼就能夠去排查這個類是否用法有問題了。
六、還可使用jstat(Java命令學習系列(四)——jstat)來查看GC狀況,看看是否有頻繁FGC,而後再使用jmap(Java命令學習系列(三)——Jmap)來dump內存,查看是否存在內存泄露。