java运维:负载分析及问题排查极简教程(linux+java)
- 格式:pdf
- 大小:208.63 KB
- 文档页数:8
java运维:负载分析及问题排查极简教程(linux+java)
本⽂转载⾃微信公众号-架构师⼩秘圈
Hollis
平常的⼯作中,在衡量服务器的性能时,经常会涉及到⼏个指标,load、cpu、mem、qps、rt等。
每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴随着某些指标的异常。
⼤部分情况下,在问题发⽣之前,某些指标就会提前有异常显⽰。
对于这些指标的理解和查看、异常解决等,是程序员们重要的必备技能。
本⽂,主要来介绍⼀下⼀个⽐较重要的指标——机器负载(Load),主要涉及负载的定义、查看负载⽅式、负载飙⾼排查思路等。
什么是负载
负载(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)
简单解释⼀下:在UNIX系统中,系统负载是对当前CPU⼯作量的度量,被定义为特定时间间隔内运⾏队列中的平均线程数。
load average 表⽰机器⼀段时间内的平均load。
这个值越低越好。
负载过⾼会导致机器⽆法处理其他请求及操作,甚⾄导致死机。
Linux的负载⾼,主要是由于CPU使⽤、内存使⽤、IO消耗三部分构成。
任意⼀项使⽤过多,都将导致服务器负载的急剧攀升。
查看机器负载
在Linux机器上,有多个命令都可以查看机器的负载信息。
其中包括uptime、top、w等。
uptime命令
uptime命令能够打印系统总共运⾏了多长时间和系统的平均负载。
uptime命令可以显⽰的信息显⽰依次为:现在时间、系统已经运⾏了多长时间、⽬前有多少登陆⽤户、系统在过去的1分钟、5分钟和15分钟内的平均负载。
➜ ~ uptime
13:29up 23:41, 3 users, load averages: 1.74 1.87 1.97
这⾏信息的后半部分,显⽰"load average",它的意思是"系统的平均负荷",⾥⾯有三个数字,我们可以从中判断系统负荷是⼤还是⼩。
1.74 1.87 1.97这三个数字的意思分别是1分钟、5分钟、15分钟内系统的平均负荷。
我们⼀般表⽰为load1、load5、load15。
w命令
w命令的主要功能其实是显⽰⽬前登⼊系统的⽤户信息。
但是与who不同的是,w命令功能更加强⼤,w命令还可以显⽰:当前时间,系统启动到现在的时间,登录⽤户的数⽬,系统在最近1分钟、5分钟和15分钟的平均负载。
然后是每个⽤户的各项数据,项⽬显⽰顺序如下:登录帐号、终端名称、远程主机名、登录时间、空闲时间、JCPU、PCPU、当前正在运⾏进程的命令⾏。
➜ ~ w
14:08up 23:41, 3 users, load averages: 1.74 1.87 1.97
USER TTY FROM LOGIN@ IDLE WHAT
hollis console - 六1423:40 -
hollis s000 - 六1420: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的任务管理器。
上⾯的输出结果中,Load Avg: 1.74, 1.87, 1.97显⽰的就是负载信息。
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中的某些线程被长时间占⽤、⼤量内存持续占⽤等导致。
建议从以下⼏个⽅⾯排查代码问题:
1、是否有内存泄露导致频繁GC
2、是否有死锁发⽣
3、是否有⼤字段的读写
4、会不会是数据库操作导致的,排查SQL语句问题。
这⾥还有个建议,如果发现线上机器Load飙⾼,可以考虑先把堆栈内存dump下来后,进⾏重启,暂时解决问题,然后再考虑回滚和排查问题。
Java Web应⽤Load飙⾼排查思路
1、使⽤uptime查看当前load,发现load飙⾼。
➜ ~ uptime
13:29up23:41, 3 users, load average s:101010
2、使⽤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.26java
发现PID为1893的进程占⽤CPU 181%。
⽽且是⼀个Java进程,基本断定是软件问题。
3、使⽤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.11java
4、使⽤printf命令查看这个线程的16进制
➜ ~ printf %x4519
11a7
5、使⽤jstack命令查看当前线程正在执⾏的⽅法。
➜ ~ jstack 1893 |grep -A 20011a7
"thread-5" #500 daemon prio=10 os_prio=0 tid=0x00007f632314a800 nid=0x11a2 runnable [0x000000005442a000]
ng.Thread.State: RUNNABLE
at sun.misc.URLClassPath$Loader.findResource(URLClassPath.jav a:684)
at sun.misc.URLClassPath.findResource(URLClassPath.jav a:188)
at .URLClassLoader$2.run(URLClassLoader.jav a:569)
at .URLClassLoader$2.run(URLClassLoader.jav a:567)
at java.security.AccessController.doPrivileged(Native Method)
at .URLClassLoader.findResource(URLClassLoader.jav a:566)
at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.jav a:248)
at com.hollis.test.util.BeanValidator.validate(BeanValidator.jav a:30)
从上⾯的线程的栈⽇志中,可以发现,当前占⽤CPU较⾼的线程正在执⾏我代码的com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)类。
那么就可以去排查这个类是否⽤法有问题了。
6、还可以使⽤jstat来查看GC情况,看看是否有频繁FGC,然后再使⽤jmap来dump内存,查看是否存在内存泄露。
平常的⼯作中,在衡量服务器的性能时,经常会涉及到⼏个指标,load、cpu、mem、qps、rt等。
每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴随着某些指标的异常。
⼤部分情况下,在问题发⽣之前,某些指标就会提前有异常显⽰。
对于这些指标的理解和查看、异常解决等,是程序员们重要的必备技能。
本⽂,主要来介绍⼀下⼀个⽐较重要的指标——机器负载(Load),主要涉及负载的定义、查看负载⽅式、负载飙⾼排查思路等。
什么是负载
负载(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)
简单解释⼀下:在UNIX系统中,系统负载是对当前CPU⼯作量的度量,被定义为特定时间间隔内运⾏队列中的平均线程数。
load average 表⽰机器⼀段时间内的平均load。
这个值越低越好。
负载过⾼会导致机器⽆法处理其他请求及操作,甚⾄导致死机。
Linux的负载⾼,主要是由于CPU使⽤、内存使⽤、IO消耗三部分构成。
任意⼀项使⽤过多,都将导致服务器负载的急剧攀升。
查看机器负载
在Linux机器上,有多个命令都可以查看机器的负载信息。
其中包括uptime、top、w等。
uptime命令
uptime命令能够打印系统总共运⾏了多长时间和系统的平均负载。
uptime命令可以显⽰的信息显⽰依次为:现在时间、系统已经运⾏了多长时间、⽬前有多少登陆⽤户、系统在过去的1分钟、5分钟和15分钟内的平均负载。
➜ ~ uptime
13:29up 23:41, 3 users, load averages: 1.74 1.87 1.97
这⾏信息的后半部分,显⽰"load average",它的意思是"系统的平均负荷",⾥⾯有三个数字,我们可以从中判断系统负荷是⼤还是⼩。
1.74 1.87 1.97这三个数字的意思分别是1分钟、5分钟、15分钟内系统的平均负荷。
我们⼀般表⽰为load1、load5、load15。
w命令
w命令的主要功能其实是显⽰⽬前登⼊系统的⽤户信息。
但是与who不同的是,w命令功能更加强⼤,w命令还可以显⽰:当前时间,系统启动到现在的时间,登录⽤户的数⽬,系统在最近1分钟、5分钟和15分钟的平均负载。
然后是每个⽤户的各项数据,项⽬显⽰顺序如下:登录帐号、终端名称、远程主机名、登录时间、空闲时间、JCPU、PCPU、当前正在运⾏进程的命令⾏。
➜ ~ w
14:08up 23:41, 3 users, load averages: 1.74 1.87 1.97
USER TTY FROM LOGIN@ IDLE WHAT
hollis console - 六1423:40 -
hollis s000 - 六1420: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的任务管理器。
上⾯的输出结果中,Load Avg: 1.74, 1.87, 1.97显⽰的就是负载信息。
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中的某些线程被长时间占⽤、⼤量内存持续占⽤等导致。
建议从以下⼏个⽅⾯排查代码问题:
1、是否有内存泄露导致频繁GC
2、是否有死锁发⽣
3、是否有⼤字段的读写
4、会不会是数据库操作导致的,排查SQL语句问题。
这⾥还有个建议,如果发现线上机器Load飙⾼,可以考虑先把堆栈内存dump下来后,进⾏重启,暂时解决问题,然后再考虑回滚和排查问题。
应⽤Load飙⾼排查思路➜ ~ uptime
13:29up23:41, 3 users, load average s:101010
2、使⽤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.26java
发现PID为1893的进程占⽤CPU 181%。
⽽且是⼀个Java进程,基本断定是软件问题。
3、使⽤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.11java
4、使⽤printf命令查看这个线程的16进制
➜ ~ printf %x4519
11a7
5、使⽤jstack命令查看当前线程正在执⾏的⽅法。
➜ ~ jstack 1893 |grep -A 20011a7
"thread-5" #500 daemon prio=10 os_prio=0 tid=0x00007f632314a800 nid=0x11a2 runnable [0x000000005442a000]
ng.Thread.State: RUNNABLE
at sun.misc.URLClassPath$Loader.findResource(URLClassPath.jav a:684)
at sun.misc.URLClassPath.findResource(URLClassPath.jav a:188)
at .URLClassLoader$2.run(URLClassLoader.jav a:569)
at .URLClassLoader$2.run(URLClassLoader.jav a:567)
at java.security.AccessController.doPrivileged(Native Method)
at .URLClassLoader.findResource(URLClassLoader.jav a:566)
at org.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.jav a:248)
at com.hollis.test.util.BeanValidator.validate(BeanValidator.jav a:30)
从上⾯的线程的栈⽇志中,可以发现,当前占⽤CPU较⾼的线程正在执⾏我代码的com.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)类。
那么就可以去排查这个类是否⽤法有问题了。
6、还可以使⽤jstat来查看GC情况,看看是否有频繁FGC,然后再使⽤jmap来dump内存,查看是否存在内存泄露。