mysql进程飙高
简述
各位服务端开发的同学,在使用mysql的过程中,大概都有遇到过cpu突然飙高到的情况,比如达到了200%。数据库在执行查询或者修改数据时,系统需要消耗大量的cpu算力来维护存储系统和内存系统中数据的一致性。并发量大并且大量sql性能低的情况下,会导致cpu飙高,如果还开启了慢日志记录,会进一步导致性能恶化。
定位过程
- 使用top命令观察,确认是否由mysqlId导致
- 如果是mysqlId导致,show processlist,查看session情况,排查是否存在消耗资源的sql在执行
- 找出消耗高的sql,观察执行计划是否准确,索引是否缺失,或者实在是由于数据量过大造成。
处理办法
- 一般来说需要kill掉这些线程,同时观察cpu使用率是否下降
- 进行相应的调整(加缓存、改sql、限制连接数等)。
- 重新跑这些sql。
- 优化的过程,往往不是一步完成的,而是一步一步,执行一项优化措辞,再观察,再优化。
场景举例
某产品线上环境,cpu使用率达到900%+。首先从数据量、索引情况、缓存使用等方向入手,目测数据量不大,也就是百万级,接下来去定位索引、缓存问题。
- 经过排查,发现很多查询都是直接走mysql,没有用到缓存
- 既然没有用到缓存,则是大量请求全部查询MySQL导致。通过下面的命令查看:
show processlist;
发现类似很多相同的SQL语句,一直处于query状态中。
select id form user where user_name = 'xxxxx';
初步分析可能是 user_name 字段没有索引导致。接着查询user表的索引情况:
show index form user;
发现这个字段是没有建立索引。增加索引之后,该条SQL查询能够正常执行。
3. 没隔一会,又发生大量的请求超时问题。接着进行分析,发现是开启了 慢日志查询。大量的SQL查询语句超过慢日志设置的阀值,于是将慢日志关闭之后,速度瞬间提升。CPU的使用率基本保持在300%左右。但还不是理想状态。
4. 紧接着将部分实时查询数据的SQL语句,都通过缓存(redis)读写实现。观察一段时间后,基本维持在了70%~80%。
总结
- 不推荐在这种CPU使用过高的情况下进行慢日志的开启。因为大量的请求,如果真是慢日志问题会发生日志磁盘写入,性能很低。
- 直接通过show processlist命令查看,基本能清晰的定位出部分查询问题严重的SQL语句,在针对该SQL语句进行分析。一般可能就是索引、锁、查询大量字段、大表等问题导致。
- 再则一定要使用缓存系统,降低对MySQL的查询频次。
- 对于内存调优,也是一种解决方案。
java进程飙高
简述
java进程在不进行大量cpu运算的情况下,cpu应该在100~200%之间。但是一旦高并发场景,要么走到了死循环,要么做了大量的GC,容易导致cpu飙高至800~900%
定位过程
- 首先通过top命令查看当前占用cpu较高的进程pid
- 查看当前进程消耗cpu较高的线程pid,top -Hp pid
- 通过print命令将线程pid转为16进制,根据该16进制值去打印的堆栈日志中查询,查看该线程所驻留的方法位置。
- 通过jstack命令查看栈信息,定位到线程的具体代码
- 分析代码解决问题
处理办法
- 如果是空循环或者空自旋
处理方式:可以使用Thread.sleep或者加锁,让线程适当阻塞。 - 在循环的代码逻辑中,创建大量的新对象导致频繁GC。比如,从mysql查出了大量的数据,比如100W以上等等。
处理方式:可以减少对象的创建数量,或者,可以考虑使用 对象池。
场景举例
某产品线上环境,运行一段时间后发现对应的进程竟然占用了700%的CPU,导致服务器不堪重负,频繁宕机。
- 登录服务器,执行top命令,查看CPU占用情况,找到进程的pid
top
很容易发现,PID为29706的java进程的CPU飙升到700%多,且一直降不下来,很显然出现了问题。
2. 使用top -Hp命令查看该Java进程内所有线程的资源占用情况
top -Hp 29706
很容易发现,多个线程的CPU占用达到了90%多。我们挑选线程号为30309的线程继续分析。
3. 使用jstack命令定位代码
# printf “%x\n” 命令(tid指线程的id号)将以上10进制的线程号转换为16进制
printf "%x\n" 30309
转换后的结果分别为7665,由于导出的线程快照中线程的nid是16进制的,而16进制以0x开头,所以对应的16进制的线程号nid为0x7665
# 通过使用dk自带命令jstack获取该java进程的线程快照并输入到文件中
jstack -l 29706 > ./jstack_result.txt
在jstack_result.txt 文件中根据线程好nid搜索对应的线程描述
cat jstack_result.txt |grep -A 100 7665
根据搜索结果,判断应该是ImageConverter.run()方法中的代码出现问题
当然,这里也可以直接采用一下命令来定位具体代码行
jstack 29706 |grep -A 200 7665
- 分析代码解决问题(规避空循环、频繁GC)