当前位置: 首页 > 科技观察

服务器性能指标(一)——负载(Load)分析与排查

时间:2023-03-17 11:09:27 科技观察

在平时的工作中,衡量服务器性能时,往往会涉及到几个指标,如load、cpu、mem、qps、rt等,每个指标都有它的自己独特的意义。很多时候线上出现问题的时候,往往伴随着某些指标的异常。在大多数情况下,某些指标会在问题发生之前提前显示异常。对这些指标的理解和查看、异常的解决等,是程序员重要且必备的技能。在这篇文章中,我们将主要介绍一个比较重要的指标——机器负载(Load),主要涉及负载的定义、负载的查看方式以及负载过高的排查方式。什么是负载?负载(load)是一台linux机器的一个重要指标,它直观地反映了机器当前的状态。让我们看看负载是如何定义的:在UNIX计算中,系统负载是衡量计算机系统执行的计算工作量的指标。平均负载表示一段时间内的平均系统负载。它通常以三个数字的形式出现,分别代表最后一分钟、五分钟和十五分钟期间的系统负载。(wikipedia)简要解释:在UNIX系统中,系统负载是衡量当前CPU工作量的指标,定义为特定时间间隔内运行队列中的平均线程数。loadaverage表示机器在一段时间内的平均负载。值越低越好。过大的负载会导致机器无法处理其他请求和操作,甚至导致死机。Linux的高负载主要是三个部分造成的:CPU占用、内存占用、IO消耗。过度使用任何一个都会导致服务器负载急剧增加。查看机器负载在Linux机器上,有多个命令可以查看机器负载信息。其中包括uptime、top、w等。uptime命令uptime命令可以打印系统的总运行时间和系统的平均负载。uptime命令显示的信息是:当前时间,系统已经运行了多长时间,当前有多少用户登录,过去1分钟、5分钟、15分钟系统的平均负载。?~uptime13:29up23:41,3users,loadaverages:1.741.871.97这行信息的后半部分显示“loadaverage”,意思是“系统的平均负载”,里面有三个数字,从我们可以判断系统负载是大还是小。1.741.871.97这三个数字分别表示系统在1分钟、5分钟和15分钟内的平均负载。我们一般表示为load1、load5、load15。w命令w命令的主要作用其实就是显示当前登录系统的用户信息。但与who不同的是,w命令更强大。w命令还可以显示:当前时间、自系统启动以来的时间、登录用户数、最近1分钟、5分钟和15分钟系统的平均负载。然后是每个用户的各种数据,项目依次显示:登录账号、终端名、远程主机名、登录时间、空闲时间、JCPU、PCPU、当前运行进程的命令行。?~w14:08up23:41,3users,loadaverages:1.741.871.97USERTTYFROMLOGIN@IDLEWHATHollisconsole-six1423:40-holliss000-six??1420:24-zshholliss001-six15-w从上面w命令的结果可以看出当前系统时间14:08,系统启动至今23小时41分钟,一共3个用户登录,过去1分钟、5分钟、15分钟系统平均负载为1.74分别为1.87和1.97。这与正常运行时间得到的结果相同。下面还打印了一些登录用户的数据,这里就不详细介绍了。top命令top命令是Linux下常用的性能分析工具。它可以实时显示系统中各个进程的资源使用情况,类似于Windows的任务管理器。?~topProcesses:244total,3running,9stuck,232sleeping,1484threads14:16:01LoadAvg:1.74,1.87,1.97CPUusage:8.0%user,6.79%sys,85.19%idleSharedLibs:116Mresident,16Mdata,14Mlinkedit.Memresidenthymshared.6P630prionReg2s,8.0%user,6.79%sys,85.19%idleSharedLibs:7819Mused(1692Mwired),370Munused.VM:682Gvsize,533Mframeworkvsize,6402060(0)swapins,7234356(0)swapouts.Networks:packets:383006/251Min,334448/60Mout.88/Disks:25103540GCPUDCOM%.PIDMANTHwritten#WQ#PORTMEMPURGCMPRSPGRPPPIDSTATEBOOSTS%CPU_ME%CPU_OTHRSUIDFAULTSCOWMSGSENTMSGRECVSYSBSDSYSMACHCSW30845top3.000:00.491/10213632K0B0B308451394running*0[1]0.000000.0000003283+112203556+101770+8212+119901+823+30842GoogleChrom0.000:47.39170155130M0B0B11461146sleeping*0[1]0.000000.00000501173746269711767837821364228444830310043Intheoutput上面,LoadAvg:1.74,1.87,1.97显示了负载信息。机器的正常负载范围对于机器负载多少才算正常,一直以来争议很大,不同的人有不同的理解。对于单个CPU,有人认为Load超过0.7就超出了正常范围。有人认为只要不超过1就可以了。也有人认为单个CPU的负载在2以下是可以接受的。为什么会有这么多不同的理解?这是因为不同的机器除了CPU的影响外,还有其他因素。运行的程序、机器内存,甚至机房的温度都可能不一样。例如,一些机器用于定期执行大量正在运行的批处理任务。这段时间Load可能会飙升的比较高。其他时间可能会更低。那么在这段飙升的高位期间,我们是否应该排查问题呢?我的建议是,最好根据自己机器的实际情况,建立一个指标的基线(比如上个月的平均值)。只要每天的负荷在基线范围内不是太大,就可以接受。需要人为干预。但是,必须始终有一个关于此值的建议阈值。阮一峰在博客中提出如下建议:当系统负载持续大于0.7时,就要开始排查问题所在,防止情况进一步恶化。当系统负载持续大于1.0时,必须手动寻找降低该值的方案。当系统负载达到5.0时,说明你的系统出现严重问题,长时间无响应,或接近崩溃。您不应让系统达到此值。以上指标是基于单CPU的,但是现在很多电脑都是多核的。因此,对于一般的系统来说,是根据CPU的数量来判断系统是否已经过载(OverLoad)。如果我们认为0.7是单核机器负载的安全线,那么四核机器负载最好保持在3以下(4*0.7=2.8)。还有一点需要提及。在LoadAvg指标中,有三个值,1分钟系统负载,5分钟系统负载,15分钟系统负载。我们在排查问题的时候也可以参考这三个值。通常,1分钟的系统负载表示最近的瞬变。15分钟的系统负载表示持续存在的现象,而不是暂时的问题。如果load15高而load1低,事情可以认为更好。相反,情况可能会变得更糟。如何降低负载负载高的原因可能很复杂,可能是硬件问题,也可能是软件问题。如果是硬件问题,说明机器性能确实不行,所以解决方法很简单,直接换机器就行了。前面我们提到,CPU占用、内存占用、IO消耗都会导致高负载。如果是软件问题,可能是Java中的某些线程被长时间占用,或者大量内存被持续占用导致的。建议从以下几个方面排查代码问题:1.是否存在内存泄漏导致频繁GC。2、是否有死锁。3、是否有大字段的读写。4、是否是数据库操作引起的,排查SQL语句问题。这是另一个建议。如果发现线上机器负载飙升,可以考虑先转储栈内存,然后重启暂时解决问题,再考虑回滚排除故障。1、使用uptime查看当前负载,发现负载在飙升。?~正常运行时间13:29up23:41,3用户,平均负载:1010102。使用top命令查看CPU占用率高的进程号。?~topPIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND1893admin2007127m2.6g38mS181.732.610:20.26java发现PID为1893的进程占用了181%的CPU。而且是Java进程,基本确定是软件问题。3.使用top命令查看哪个线程占用率高?~top-Hp1893PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND4519admin2007127m2.6g38mR18.632.60:40.11java4.使用printf命令查看本线程十六进制?~printf%x451911a75,使用jstack命令查看当前线程正在执行的方法。(Java命令学习系列(二)——Jstack)?~jstack1893|grep-A20011a7"thread-5"#500daemonprio=10os_prio=0tid=0x00007f632314a800nid=0x11a2runnable[0x000000005442a000]java.langun.LosourceRefinderLEURL.States(URLClassPath.java:684)atsun.misc.URLClassPath.findResource(URLClassPath.java:188)atjava.net.URLClassLoader$2.run(URLClassLoader.java:569)atjava.net.URLClassLoader$2.run(URLClassLoader.java:567)atjava.security.AccessController.doPrivileged(NativeMethod)atjava.net.URLClassLoader.findResource(URLClassLoader.java:566)atorg.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248)atcom.hollis.test.util.BeanValidator.validate(BeanValidator.java:30)从上面线程的stacklog可以发现当前占用CPU高的线程正在执行我代码的com.hollis.test.util.BeanValidator。验证(BeanValidator.java:30)类。然后你可以检查这个类的使用是否有问题。6、也可以使用jstat(Java命令学习系列(四)——jstat)查看GC情况,看是否有频繁的FGC,然后使用jmap(Java命令学习系列(三)——Jmap)dump内存,检查内存泄漏。【本文为专栏作家霍利斯原创文章,作者微信公众号Hollis(ID:hollishuang)】点此阅读更多本作者好文