当前位置: 首页 > Linux

老公,人家线上服务CPU 100%了,肿么办嘛

时间:2023-04-06 19:18:11 Linux

老公,在线服务CPU100%,怎么办?尤其是周末或者半夜的时候,群里突然有人反映线上机器负载极高。不熟悉定位流程和思路的同学,登录服务器的时候可能手忙脚乱,定位流程来来回回。对此,不少同学整理出了相关的流程或方法。这类似于将大象放入冰箱需要多少步。传统方案一般是4步:topoderbywithP:1040//先按进程负载排序找到axLoad(pid)top-HpProcessPID:1073//找到相关负载线程PIDprintf"0x%x\n"ThreadPID:0x431//将线程PID转成16进制,为后面查找jstack日志做准备jstackprocessPID|vim+/hexadecimalthreadPID-//例如:jstack1040|vim+/0x431-但对于在线问题定位,分秒必争。以上4个步骤还是太繁琐费时了。能不能把它打包成一个Tool,出现问题的时候一键定位,秒级找到问题代码行?当然!工具链的成熟度不仅体现了一个开发者的运维能力,更体现了开发者的效率意识。淘宝的oldratlee将上述过程打包成一个工具:show-busy-java-threads.sh,在线上可以很方便的定位到此类问题。下面我举两个例子看看实际效果。快速安装使用:`source<(curl-fsSLhttps://raw.githubusercontent.com/oldratlee/useful-scripts/master/test-cases/self-installer.sh)`1、java正规表达式回源生成CPU100%`importjava.util.ArrayList;``importjava.util.List;``importjava.util.regex.Matcher;``importjava.util.regex.Pattern;``publicclassRegexLoad{``publicstaticvoidmain(String[]args){``String[]patternMatch={"([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)",``"([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)"};``ListpatternList=newArrayList();``patternList.add("AvgVolumeUnitsproductA+VolumeUnitsproductA”);``patternList.add("AvgVolumeUnits/VolumeUnitsproductA");```patternList.add("AvgretailerOnHand/VolumeUnitsPlan/StoreCount");``patternList.add("Avg手量单位计划商店计数");``patternList.add("1-平均商户量单位");``patternList.add("Total零售商发货计数”);``for(Strings:patternList){``for(inti=0;i``show-busy-java-threads.sh-c<要显示的线程堆栈数>-p<指定的Java进程>``#-F选项:执行jstack命令时添加-F选项(强制jstack),一般不需要使用``show-busy-java-threads.sh-p-F``show-busy-java-threads.sh-s<指定jstack命令的完整路径>``#对于sudo模式的运行,JAVA_HOME环境变量不能传递给root,``#root用户经常这样做没有配置JAVA_HOME,配置不方便,``#显式指定jstack命令的路径更方便``show-busy-java-threads.sh-a<记录输出的文件>``show-busy-java-threads.sh-t<重复执行次数>-i<重复执行间隔秒数>``#默认执行一次;默认执行间隔为3秒``################################``#注意:``###############################``#如果Java进程的用户和当前执行脚本的用户不同,jstack将无法使用此Java进程。``#为了能够切换到Java进程的用户,需要加上sudo来执行,可以解决:``sudoshow-busy-java-threads.sh`例子:`work@dev_zz_Master10.48.186.3223:45:50~/demo>``bashshow-busy-java-threads.sh``[1]繁忙(96.2%)线程(8577/0x2181)用户下的java进程(8576)堆栈(工作):``"main"prio=10tid=0x00007f0c64006800nid=0x2181runnable[0x00007f0c6a64a000]``java.lang.Thread.State:RUNNABLE``atjava.util.regex.Pattern$GroupHead.match(Pattern.java:4168)``atjava.util.regex.Pattern$Loop.match(Pattern.java:4295)``...``atjava.util.regex.Matcher.match(Matcher.java:1127)``在java.util.regex.Matcher。matches(Matcher.java:502)``在RegexLoad.main(RegexLoad.java:27)``[2]用户(工作)下的java进程(8576)的繁忙(1.5%)线程(8591/0x218f)堆栈:``"C2CompilerThread1"daemonprio=10tid=0x00007f0c64095800nid=0x218f等待条件[0x0000000000000000]``java.lang.Thread.State:RUNNABLE``[3]Busy(0.8%)8e0thread(8ofjava用户下的进程(8576)(work):``"C2CompilerThread0"daemonprio=10tid=0x00007f0c64093000nid=0x218e等待条件[0x0000000000000000]``java.lang.Thread.State:RUNNABLE``[4]忙(0.85%)3线程0x2191)用户(工作)下的Java进程(8576)堆栈:``“VM定期任务线程”prio=10tid=0x00007f0c640a2800nid=0x2191等待条件``[5]忙(0.1%)线程(25149/0x62)堆栈用户(工作)下的java进程(25137):``“VMPeriodicTaskThread”prio=10tid=0x00007f13340b4000nid=0x6247等待条件``work@dev_zz_Master10.48.186.3223:46:0>`你可以看到一键直接定位到异常代码行很方便?2.线程死锁,程序挂了intindex;``publicstaticvoidmain(String[]a){``Threadt1=newThread1();``Threadt2=newThread2();``t1.start();``t2.start();``}``私有静态类Thread1ext结束线程{``publicvoidrun(){``synchronized(l1){``System.out.println("Thread1:Holdinglock1...");``try{Thread.sleep(10);}``catch(InterruptedExceptione){}``System.out.println("Thread1:Waitingforlock2...");``synchronized(l2){``System.out.println("Thread2:持有锁1&2...");``}``}``}``}``privatestaticclassThread2extendsThread{``publicvoidrun(){``synchronized(l2){``System.out.println("Thread2:Holdinglock2...");``try{Thread.sleep(10);}``catch(InterruptedExceptione){}``System.out.println("Thread2:Waitingforlock1...");``synchronized(l1){``System.out.println("Thread2:Holdinglock2&1...");``}``}``}``}``}`执行后的效果:如何使用工具定位:一键定位:可以清楚的看到线程互相锁定了对方的资源等待,导致死锁,直接定位到代码行和具体原因通过上面两个例子,我想同学们应该对这个工具有了更深的了解,它能解决什么问题.如果遇到CPU100%的问题,就不能再慌了。但是更多的人还是要靠大家去修炼。毕竟熟能生巧~3.免费实用的脚本工具大礼包除了文中提到的show-busy-java-threads.sh,oldratlee还整合集成了很多常用的过程中涉及的脚本工具开发和运维,我觉得特别有用的,简单罗列如下:(1)show-duplicate-java-classes偶尔会遇到莫名其妙的类异常,在本地开发测试很正常,但是上线后,经过大量的辛苦了,发现原因是Jar冲突!这个工具可以在JavaLib(Java库,即Jar文件)或者Class目录(类目录)中找到重复的类。Java开发一个比较头疼的问题就是Jar冲突(即多个版本的Jar),或者重复的类。会出现NoSuchMethod等问题,但到时候可能不是问题。找出有重复类的Jar,可以防患于未然。`#查找当前目录下所有Jar中的重复类``show-duplicate-java-classes``#查找多个指定目录下所有Jar中的重复类``show-duplicate-java-classespath/to/lib_dir1/path/to/lib_dir2``#在多个指定的Class目录中查找重复的类。Class目录由-c选项指定``show-duplicate-java-classes-cpath/to/class_dir1-c/path/to/class_dir2``#在指定的Class目录下查找重复类的Jar和所有指定目录下的jar``show-duplicate-java-classespath/to/lib_dir1/path/to/lib_dir2-cpath/to/class_dir1-cpath/to/class_dir2`例如:`#在war模块中执行directorytogenerateawarfile``$mvninstall``...``#解压war文件,war文件包含应用程序依赖的Jar文件``$unziptarget/*.war-dtarget/war``...``#检查重复类``$show-duplicate-java-classes-ctarget/war/WEB-INF/classestarget/war/WEB-INF/lib``...`(2)find-in-jars在当前目录下在所有的jar文件中,查找类或者资源文件。用法:注意后面的Pattern是grep的扩展正则表达式。`find-in-jars'log4j\.properties'``find-in-jars'log4j\.xml$'-d/path/to/find/directory``find-in-jarslog4j\\.xml``find-in-jars'log4j\.properties|log4j\.xml'`示例:`$./find-in-jars'Service.class$'``./WEB-INF/libs/spring-2.5.6。SEC03.jar!org/springframework/stereotype/Service.class``./rpc-benchmark-0.0.1-SNAPSHOT.jar!com/taobao/rpc/benchmark/service/HelloService.class`(3)housemdpid[java\_home]很早以前,我们使用BTrace来解决问题。在感叹BTrace强大的同时,我们折腾了好几次,挂了线上系统。2012年,淘宝巨石写了HouseMD,整合了几个常用的Btrace脚本,形成一个独立风格的应用。其核心代码使用Scala,HouseMD是一个基于字节码技术的诊断工具。因此,除了Java之外,任何最终以字节码形式运行在JVM上的语言,HouseMD都支持对它们进行诊断,例如Clojure(感谢@Killme2008提供了使用介绍)、scala、Groovy、JRuby、Jython、kotlin等。使用housemd跟踪java程序的运行时间,支持的操作有:查看加载类跟踪方法查看环境变量查看对象属性值详情请参考:https://github.com/CSUG/House...(4)jvmpid执行jvm调试工具,包括查看java栈、堆、线程、gc等状态,支持的功能有:`========线程相关========``1:查看CPU使用率最高线程状态``2:打印所有线程``3:打印线程数``4:按线程状态统计线程数``========GC相关=======``5:垃圾收集统计(包括原因)可以指定间隔时间和执行次数,默认1秒,10次``6:显示每次的空间generationintheheap可以指定间隔时间和执行次数,默认1秒,5次``7:垃圾收集统计。可以指定间隔时间和执行次数,默认1秒,10次``8:打印perm区的内存状态*会导致程序暂停响应*``9:查看directbuffer状态``========堆对象相关=======```10:dumpheaptoafile*会导致程序暂停响应*默认保存到`pwd`/dump.bin,您可以指定其他路径```11:触发完整的gc。*它会导致程序暂停响应*``12:打印jvm堆统计信息*它会导致程序暂停响应*``13:打印jvm堆中的top20对象。*会导致程序暂停响应*参数:1:按实例数排序,2:按内存占用排序,默认为1``14:触发fullgc后,打印jvm堆中的top20个对象.*会导致程序暂停响应*参数:1:按实例数排序,2:按内存占用排序,默认为1``15:输出perm中类加载器生成的所有对象。可以指定间隔时间和执行次数``=========Others=======``16:打印finalzer队列状态``17:显示classloader统计信息``18:显示jit编译statistics``19:死锁检测``20:等待X秒,默认为1``q:exit`进入jvm工具后,可以输入序号执行相应的命令。可以一次执行多条命令,用分号“;”隔开,如:1;3;4;5;6每条命令可以有参数,用冒号“:”隔开,同一个命令的参数以逗号分隔,如:输入commandqueue:1;5:1000,100;10:/data1/output.bin(5)greys[@IP:PORT]PS:目前Grays只支持Java6+的Linux/Unix/Mac,Windows暂不支持。Grays是JVM进程执行过程中的异常诊断工具。在不中断程序执行的情况下轻松解决问题。和HouseMD一样,Greys-Anatomy将这部美剧命名为同名的《实习医生格蕾》,以此向前辈致敬。写代码的时候参考了BTrace和HouseMD两位前辈的思路。使用greys在运行时跟踪java程序(不传参,需要先greys-Cpid,再greys)。支持的操作有:查看加载类、方法信息查看JVM当前基本信息方法执行监控(调用量、失败率、响应时间等)方法执行数据观察、记录和回放(参数、返回结果、异常信息等))方法调用跟踪渲染的详细信息请参考:https://github.com/oldmanpush...(6)sjksjk--commandssjk--help使用sjk来诊断、检查性能和优化Java工具ttop:监控指定jvm进程的每个线程的cpu使用情况jps:增强版hh:jmap-histo增强版gc:实时上报垃圾回收信息更多信息请参考:github.com/aragozin/jvm-tools参考:oldratlee/useful-scriptsgithub.com/oldratlee/useful-scriptsawesome-scriptsgithub.com/superhj1987/awesome-scriptsJDK内置工具排错场景示例bit.ly/2xtukcbJava调优经验talkbit.ly/2xCIj2Ljvm故障排除工具箱jvm-toolssegmentfault.com/a/1190000012658814alibaba/arthasgithub.com/alibaba/arthas/blob/7f236219ddbd040764dd821cbcbd44899dd57c90/README.md来源:my.os4jun8010.net