Load 服务器性能指标——负载分析及问题排查( 二 )


为什么会有这么多不同的理解呢,是因为不同的机器除了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中的某些线程被长时间占用、大量内存持续占用等导致 。建议从以下几个方面排查代码问题:
1、是否有内存泄露导致频繁GC 2、是否有死锁发生 3、是否有大字段的读写 4、会不会是数据库操作导致的,排查SQL语句问题 。
这里还有个建议,如果发现线上机器Load飙高,可以考虑先把堆栈内存dump下来后,进行重启,暂时解决问题,然后再考虑回滚和排查问题 。
Java Web应用Load飙高排查思路1、使用uptime查看当前load,发现load飙高 。
?~ uptime13:29up 23:41, 3 users, load averages: 10 10 10复制代码2、使用top命令,查看占用CPU较高的进程ID 。
?~ topPID USERPRNIVIRTRESSHR S %CPU %MEMTIME+COMMAND1893 admin200 7127m 2.6g38m S 181.7 32.610:20.26 java复制代码发现PID为1893的进程占用CPU 181% 。而且是一个Java进程,基本断定是软件问题 。
3、使用 top命令,查看具体是哪个线程占用率较高
?~ top -Hp 1893PID USERPRNIVIRTRESSHR S %CPU %MEMTIME+COMMAND4519 admin200 7127m 2.6g38m R 18.6 32.60:40.11 java复制代码4、使用printf命令查看这个线程的16进制
?~ printf %x 451911a7复制代码5、使用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: RUNNABLEat 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)类 。那么就可以去排查这个类是否用法有问题了 。
6、还可以使用jstat(Java命令学习系列(四)——jstat)来查看GC情况,看看是否有频繁FGC,然后再使用jmap(Java命令学习系列(三)——Jmap)来dump内存,查看是否存在内存泄露 。

作者:HollisChuang


推荐阅读