在国外开发者平台HankerRank发布的2018年开发者技能调查报告中,有一项关于“哪些核心能力最受雇主重视”的调查。、编程语言熟练、Debug、系统设计和性能优化。解决问题的能力以很高的比例排在第一位,这也是为什么在很多面试的时候,面试官喜欢问这样的问题:你在这个项目中遇到的最大的挑战是什么?如何解决?如果在线出现告警如何处理?你曾经解决过任何在线问题吗?你能列出几个你知道的排查Linux服务器在线问题的命令吗?这些都是比较常见的问题,一些比较具体的问题也是建议很多开发者需要掌握的,比如:在线服务器高负载如何排查?如何解决在线服务器上CPU使用率高的问题?如何排查线上服务器频繁FullGC?如何解决在线服务器上的死锁问题?这些问题的回答,一方面考察面试官是否有很强的实践经验,另一方面也能体现出他解决问题的能力。毋庸置疑,作为开发人员,定位问题和解决问题的能力是至关重要的。因为线上一旦出现问题,比如CPU占用率高,如果不及时解决,很容易导致网站响应慢,服务器宕机等问题。所以,这本书又回到了主要故事。在本文中,我们将简要介绍在线服务器CPU占用率过高时如何排查和定位问题。1.问题发现本文是从一个真实的案例整理而来的,是楼主的生意。这个问题是在大促前的压力测试中发现的。在每次大促之前,我们的测试人员都会对网站进行压力测试。这时候他们会检查服务的cpu、内存、负载、rt、qps等指标。在一次压测中,测试人员发现我们其中一个接口在qps升到500后CPU占用率急剧上升。CPU占用率,也就是CPU占用率。顾名思义,CPU利用率是用来描述CPU的使用情况,表示CPU在一段时间内被占用。使用率越高,说明此时你的机器正在运行很多程序,反之亦然。2.问题定位如果遇到此类问题,首先要登录服务器查看具体情况。定位进程登录服务器,执行top命令,查看CPU使用情况:$topPIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND1893admin2007127m2.6g38mS181.732.610:20.26javatop命令是Linux下常用的性能分析工具,可以实时显示系统中各个进程的资源使用情况,类似于Windows的任务管理器。通过上面的命令,我们可以看到进程号为1893的Java进程的CPU使用率已经达到了181%,基本可以定位是我们的Java应用导致了整个服务器的CPU使用率飙升。我们知道Java是单进程多线程的,那么我们看看PID=1893的Java进程中各个线程的CPU占用情况,同样使用top命令:$top-Hp1893PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND4519admin2007127m2.6g38mR18.632.60:40.11java通过top-Hp1893命令可以发现,在当前1893进程中,ID为4519的线程占用的CPU最高。定位代码通过top命令,我们已经定位到了具体导致CPU占用率高的线程,那么我们来定位是哪一行代码有问题。首先,我们需要将线程4519转换成16进制:$printf%x451911a7接下来通过jstack命令查看堆栈信息:$sudo-uadminjstack1893|grep-A20011a7"HSFBizProcessor-DEFAULT-8-thread-5"#500daemonprio=10os_prio=0tid=0x00007f632314a800nid=0x11a2runnable[0x000000005442a000]java.lang.Thread.State:RUNNABLEatsun.misc.URLClassPath$Loader.findResource(URLClassPath.java:684)atsun.misc.URLClassPath1Class8findResource(URLClassPath1Class8findResource)javaat:URL.net.URLClassLoader$2.运行(URLClassLoader.java:569)在java.net.URLClassLoader$2.run(URLClassLoader.java:567)在java.security.AccessController.doPrivileged(NativeMethod)atjava.net.URLClassLoader.findResource(URLClassLoader.java:566)atjava.lang.ClassLoader.getResource(ClassLoader.java:1093)atjava.net.URLClassLoader.getResourceAsStream(URLClassLoader.java:232)atorg.hibernate.validator.internal.xml.ValidationXmlParser.getInputStreamForPath(ValidationXmlParser.java:248)atorg.hibernate.validator.internal.xml.ValidationXmlParser.getValidationConfig(ValidationXmlParser.java:191)atorg.hibernate.validator.internal.xml.ValidationXmlParser.parseValidationXml(ValidationXmlParser.java:65)atorg.hibernate.validator.internal.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:287)atorg.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:174)atjavax.validation.Validation.buildDefaultValidatorFactory(Validation.java:111)atcom.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。此外,还可以使用阿里巴巴的开源工具Arthas排查线上问题。针对以上问题,可以使用如下命令定位:thread-n3//查看CPU占用率前三位在线程之上,本文介绍如何排查线上服务器CPU占用率高的问题。有兴趣的可以在后面介绍一些高负载、频繁GC等问题的排查方法。
