【64期】MySQL 服务占用cpu ,如何排查问题? (MySQL面试第七弹)
一、引子
二、问题复现
三、问题排查
3.1 核心排查步骤
执行
top
命令:查看所有进程占系统CPU的排序。极大可能排个的就是咱们的java进程(COMMAND列)。PID那一列就是进程号。执行
top -Hp 进程号
命令:查看java进程下的所有线程占CPU的情况。执行
printf "%x\n 10
命令 :后续查看线程堆栈信息展示的都是十六进制,为了找到咱们的线程堆栈信息,咱们需要把线程号转成16进制。例如,printf "%x\n 10-》打印:a,那么在jstack中线程号就是0xa.执行
jstack 进程号 | grep 线程ID
查找某进程下-》线程ID(jstack堆栈信息中的nid)=0xa的线程状态。如果"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable
,个双引号圈起来的就是线程名,如果是“VM Thread”这就是虚拟机GC回收线程了执行
jstat -gcutil 进程号 统计间隔毫秒 统计次数(缺省代表一致统计)
,查看某进程GC持续变化情况,如果发现返回中FGC很大且一直增大-》确认Full GC! 也可以使用jmap -heap 进程ID
查看一下进程的堆内从是不是要溢出了,特别是老年代内从使用情况一般是达到阈值(具体看垃圾回收器和启动时配置的阈值)就会进程Full GC。执行
jmap -dump:format=b,file=filename 进程ID
,导出某进程下内存heap输出到文件中。可以通过eclipse的mat工具查看内存中有哪些对象比较多。
3.2 原因分析
1.内存消耗过大,导致Full GC次数过多
多个线程的CPU都超过了,通过jstack命令可以看到这些线程主要是垃圾回收线程-》上一节步骤2
通过jstat命令监控GC情况,可以看到Full GC次数非常多,并且次数在不断增加。--》上一节步骤5
生成大量的对象,导致内存溢出-》执行步骤6,查看具体内存对象占用情况。
内存占用不高,但是Full GC次数还是比较多,此时可能是代码中手动调用 System.gc()导致GC次数过多,这可以通过添加 -XX:+DisableExplicitGC来禁用JVM对显示GC的响应。
2.代码中有大量消耗CPU的操作,导致CPU过高,系统运行缓慢;
3.由于锁使用不当,导致死锁。
4.随机出现大量线程访问接口缓慢。
"http-nio-8080-exec-4" #31 daemon prio=5 os_prio=31 tid=0x00007fd08d0fa000 nid=0x6403 waiting on condition [0x00007000033db000]
java.lang.Thread.State: TIMED_WAITING (sleeping)-》期限等待
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.*.user.controller.UserController.detail(UserController.java:18)-》业务代码阻塞点
5.某个线程由于某种原因而进入WAITING状态,此时该功能整体不可用,但是无法复现;
"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9de08c7000 nid=0x5603 waiting on condition [0x0000700001f89000]
java.lang.Thread.State: WAITING (parking) ->无期限等待
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
at com.*.SyncTask.lambda$main$0(SyncTask.java:8)-》业务代码阻塞点
at com.*.SyncTask$$Lambda$1/1791741888.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
四、总结
相关文章