大家好,我是陈~[星球]()小伙伴面试网易,遇到一个性能相关的面试题:CPU飙升900%,怎么办?很遗憾,这家伙并没有理想地回答上述问题。最终,他的网易之旅在第二面结束。可惜关注公众号:码猿技术专栏,回复关键词:1111获取阿里内部Java性能调优手册!首先说明一下问题:CPU飙升200%以上是生产中很容易出现的场景:1:MySQL进程飙升900%大家都在用MySQL进程,想必大家都遇到过CPU突然变得过高,或者达到200%以上的情况。当数据库进行查询或数据修改操作时,系统需要消耗大量的CPU资源来维护存储系统和内存中数据的一致性。当并发量大,大量SQL执行性能低下时,比如字段没有索引,快的CPU会飙升。如果还启用了慢速日志记录,性能将进一步恶化。有一个MYSQL在生产中飙升900%的糟糕情况。场景二:Java进程飙升900%。一般来说,Java进程不会做大量的CPU操作。正常情况下,CPU占用率应该在100%到200%之间。大量的GC容易出现这种CPU飙升,CPU飙升900%是完全有可能的。其他场景:其他类似Redis、Nginx等进程暴涨900%的场景陈提醒:你介绍场景的时候说主要涉及两个场景,Java进程暴涨900%,MySQL进程飙升了900%。其实这两个场景就足够聊很久了。其他人,只是使用规避技术来避免它。场景一:MySQL进程CPU飙升到900%,怎么办?定位进程:使用top命令观察,判断是mysqld还是其他原因造成的。如果是mysqld引起的,showprocesslist,查看session状态,判断是否有耗费资源的SQL在运行。找到高消耗的sql,查看执行计划是否准确,是否缺少索引,或者是数据过多导致的。处理过程:杀掉这些线程(同时观察cpu使用率是否下降),一般来说,必须杀掉这些线程(同时观察cpu使用率是否下降),并做相应的调整(比如加索引,改sql,改内存参数),然后重新运行这些SQL。是否缺少索引,做相应的调整(比如加索引,改sql,改内存参数),如果是,则建立索引。也有可能每个sql并没有消耗多少资源,但是突然间,连接了大量的session,cpu飙升。这种情况下,就需要分析为什么连接数会随着应用激增,然后做出相应的调整。比如限制连接数这样的优化过程,往往不是一步完成的,而是一步一步的,实现一个优化的写法,然后观察,再优化。场景一真实案例:MySQL数据库优化真实案例陈提醒:以下案例均来自网络。作为参考,准备一个你自己的案例。我自己也遇到过这个问题。之前开发同事写的SQL语句导致线上CPU过高,MySQL的CPU占用率达到了900%+,最后通过优化降低到70%~80%。说说我个人在这个过程中的考察思路。首先,我们需要定位问题,而不是盲目启用慢日志。在大量SQL并发量大、性能低下的情况下,启用慢日志无意将MySQL推向崩溃的边缘。遇到这种情况,我分析了当前的数据量、索引情况、缓存使用情况。目测数据量并不大,只有几百万。接下来就是定位索引和缓存的问题了。查询后发现,很多查询都是通过MySQL进行的,并没有使用缓存。由于没有使用缓存,是大量请求全部查询MySQL造成的。通过以下命令查看:showprocesslist;发现有很多类似的SQL语句,一直处于查询状态。选择idformuserwhereuser_code='xxxxx';初步分析可能是user_code字段没有索引造成的。然后查询user表的索引:showindexformuser;发现这个字段没有被索引。添加索引后,SQL查询就可以正常执行了。3、过了一段时间,又出现大量请求超时的问题。然后经过分析,发现是开启了慢日志查询。大量的SQL查询语句超过慢日志设置的阈值,所以关闭慢日志后,速度瞬间提升。CPU使用率基本维持在300%左右。但这还不理想。4、紧接着,部分实时查询数据的SQL语句是通过缓存(redis)读写实现的。观察一段时间后,基本维持在70%~80%。总结:其实这次事故的解决办法很简单,就是加个索引,结合缓存使用。CPU占用率过高时不建议开启slowlog。因为大量的请求,如果真的是日志慢的问题,就会写日志磁盘,性能会极低。直接通过MySQL的showprocesslist命令查看,基本上可以很清楚的定位到一些查询问题比较严重的SQL语句,然后对SQL语句进行分析。一般可能是索引、锁、查询大量字段、大表等问题造成的。此外,必须使用缓存系统来减少对MySQL的查询频率。对于内存调优,也是一种解决方案。场景二展开:Java进程CPU飙升到900%,怎么办?定位进程:定位CPU飙升问题的一般步骤是:首先,使用top命令查看当前占用高CPU的进程的PID;查看当前消耗资源进程的线程PID:top-HpPID使用print命令将线程PID转为16进制,根据16进制值在打印的栈日志中查询,查看线程所在方法位置居住。使用jstack命令查看堆栈信息,定位到线程对应的具体代码。分析代码解决问题。处理过程:如果是空循环,或者空自旋。处理方法:可以使用Thread.sleep或者lock让线程正常阻塞。在循环的代码逻辑中,创建大量新对象会导致频繁的GC。比如从mysql中查到大量数据,比如100多W等等。处理方法:可以减少创建对象的数量,也可以考虑使用对象池。其他一些导致CPU飙升的场景,比如selector空转训练导致CPU飙升。处理方法:参考Netty源码,如果查询到一定次数的无效事件,就会重新构建选择器。JavaCPU优化700%飙升真实案例陈提醒:以下案例来自网络。作为参考,准备一个你自己的案例。最近,我负责的一个项目上线了。运行一段时间后,发现对应进程占用了700%的CPU,导致公司物理服务器不堪重负,频繁关机。那么,对于这种java进程CPU飙升的问题,我们一般是怎么定位和解决的呢?,使用top命令定位进程并登录服务器,执行top命令,查看CPU使用情况,找到进程的pidtop,很容易查到,PID为的java进程的CPU29706已经飙升到700%多了,一直没能降下来,明显有问题question。使用top-Hp命令定位线程使用top-Hp命令(Java进程的id号)查看Java进程中所有线程的资源使用情况(按shft+p按cpu使用率排序,按shift+m按内存使用率排序Sorting)这里按cpu排序:top-Hp23602很容易发现多线程的CPU使用率达到了90%以上。我们选择线程号为30309的线程继续分析。使用jstack命令定位代码1.将线程号5转为十六进制printf"%x\n"命令(tid指的是线程的id号)将上述十进制线程号转为十六进制:printf"%x\n"30309转换后的结果分别为7665。由于导出的线程快照中线程的nid是16进制的,而16进制是以0x开头的,对应的16进制的线程nid是0x76652。使用jstack命令导出线程快照使用dk自带的命令jstack获取java进程的线程快照并输入到文件中:jstack-lprocessID>./jstack_result.txt命令(进程的id号Java进程)获取线程快照结果并输入到指定文件。jstack-l29706>./jstack_result.txt3.根据线程号定位具体代码根据线程nid在j??stack_result.txt文件中查找对应的线程描述catjstack_result.txt|grep-A1007665根据搜索结果,应该是ImageConverter.run()方法中的代码有问题当然也可以直接使用jstack
