線上機器CPU負載如何解決?

 本文咱們就來簡單介紹一下,若是線上服務器發生CPU佔用率太高的問題時,應該如何排查並定位問題。html

1、發現問題

本文整理自一個真實的案例,是樓主負責的業務,在一次大促以前的壓測時發現了這個問題。java

在每次大促以前,咱們的測試人員都會對網站進行壓力測試,這個時候會查看服務的cpu、內存、load、rt、qps等指標。linux

在一次壓測過程當中,測試人員發現咱們的某一個接口,在qps上升到500之後,CPU使用率急劇升高。git

CPU利用率,又稱CPU使用率。顧名思義,CPU利用率是來描述CPU的使用狀況的,代表了一段時間內CPU被佔用的狀況。使用率越高,說明你的機器在這個時間上運行了不少程序,反之較少。github

2、定位問題

遇到這種問題,首先是登陸到服務器,看一下具體狀況。bash

定位進程服務器

登陸服務器,執行top命令,查看CPU佔用狀況:多線程

$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

top命令是Linux下經常使用的性能分析工具,可以實時顯示系統中各個進程的資源佔用情況,相似於Windows的任務管理器。ide

經過以上命令,咱們能夠看到,進程ID爲1893的Java進程的CPU佔用率達到了181%,基本能夠定位到是咱們的Java應用致使整個服務器的CPU佔用率飆升。工具

定位線程

咱們知道,Java是單進程多線程的,那麼,咱們接下來看看PID=1893的這個Java進程中的各個線程的CPU使用狀況,一樣是用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

經過top -Hp 1893命令,咱們能夠發現,當前1893這個進程中,ID爲4519的線程佔用CPU最高。

定位代碼

經過top命令,咱們目前已經定位到致使CPU使用率較高的具體線程, 那麼我麼接下來就定位下究竟是哪一行代碼存在問題。

首先,咱們須要把4519這個線程轉成16進制:

$printf %x 4519
11a7

接下來,經過jstack命令,查看棧信息:

$sudo -u admin  jstack 1893 |grep -A 200 11a7
"HSFBizProcessor-DEFAULT-8-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 java.lang.ClassLoader.getResource(ClassLoader.java:1093)
  at java.net.URLClassLoader.getResourceAsStream(URLClassLoader.java:232)
  at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248)
  at org.hibernate.validator.internal.xml.ValidationXmlParser.getValidationConfig(ValidationXmlParser.java:191)
  at org.hibernate.validator.internal.xml.ValidationXmlParser.parseValidationXml(ValidationXmlParser.java:65)
  at org.hibernate.validator.internal.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:287)
  at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:174)
  at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:111)
  at com.test.common.util.BeanValidator.validate(BeanValidator.java:30)

經過以上代碼,咱們能夠清楚的看到,BeanValidator.java的第30行是有可能存在問題的。

3、解決問題

接下來就是經過查看代碼來解決問題了,咱們發現,咱們自定義了一個BeanValidator,封裝了Hibernate的Validator,而後在validate方法中,經過Validation.buildDefaultValidatorFactory().getValidator()初始化一個Validator實例,經過分析發現這個實例化的過程比較耗時。

咱們重構了一下代碼,把Validator實例的初始化提到方法外,在類初始化的時候建立一次就解決了問題。

4、總結

以上,展現了一次比較完成的線上問題定位過程。主要用到的命令有:top 、printf 和 jstack

(1) 線上問題排查還可使用Alibaba開源的工具Arthas進行排查,以上問題,可使用一下命令定位:

thread -n 3 //查看cpu佔比前三的線程。

(2) 在top命令中,最上部其實能夠真實反映服務器的負載和cpu狀況

關於us高和ys高的問題分析:

當us值太高時,表示運行的應用消耗大量的CPU。java應用形成us高的緣由主要是線程一直處於可運行(Runnable)狀態,一般這些線程在執行無阻塞、循環、正則或純粹的計算等任務形成的;另一個可能也會形成us高的緣由是頻繁GC。

當sy值高時,表示linux花費了更多的時間在進行java線程切換。java應用形成這種現象的主要緣由是啓動的線程比較多,且這些線程多數處於不斷的阻塞(例如鎖等待,IO等待狀態)和執行狀態的變化過程當中,這就致使了操做系統要不斷地切換執行的線程,產生大量的線程上下文切換。
 

以上,本文介紹瞭如何排查線上服務器CPU使用率太高的問題,若是你們感興趣,後面能夠再介紹一些關於LOAD飆高、頻繁GC等問題的排查手段。

擴展閱讀:Java性能排查工具:阿爾薩斯

                    服務器性能指標

相關文章
相關標籤/搜索