背景
近两年处理了不少的线上环境负载飙高的问题,最近碰到的一个也比较经典,所以做个简单总结。
原因
正常CPU飙高的问题有多种,就我自己遇到的:
- 缓存穿透;
- 缓存击穿;
- 缓存雪崩;
- 内存泄漏,导致GC线程打满CPU;
- 业务内部处理问题;
- …
解决
方法1:Arthas
top
找到占用CPU高的进程;- 启动
Arthas
; thread -n 3 > /opt/top.log
命令即可以查看占用CPU最高的前3线程的堆栈信息,后面的重定向是因为真正的CPU打满以后Arthas是非常卡的更甚至不可用,并且切记Arthas的thread -n 3只能查看业务线程的堆栈信息;- 通过输出的log文件既可定位到业务问题;
- 如果发现业务线程占用很少,那基本上可以断定是内存不足或者发生内存泄漏GC线程一直在工作;
jinfo pid
查看确认进程JVM内存分配情况;jstat -gcutil pid
查看确认GC情况;- 确认是GC问题,此时就可以先尝试通过
jmap -histo pid|head -10
查看内存中占用内存Top10的大对象,有些泄漏问题是可以在此步骤定位到问题的,如果还不够接着往下走; - 输入命令
jmap -dump:format=b,file=/opt/dump.hprof pid
导出dump文件,在本地使用工具分析,在执行命令的时候需要注意,线上环境程序运行内存较大在生成期间可能会造成程序卡顿等问题,谨慎使用。工具个人推荐MAT
方法2:
Arthas因为输入植入性监控程序,在CPU被打满的情况下,是不能正常执行的,或者是非常慢,所以此方法派上用场了。
top
找到占用CPU高的进程;jstack -l pid > /opt/thread.log
输入进程内线程的堆栈信息;top -Hp pid
找到占用CPU高进程内的那些线程占用最高;- 进制转换。 jstack导出的线程id是十六进制的,所以需要将第三步得到的线程id转换为十六进制;
- 在第二步输入的文件搜索定位问题;
- 如发现是GC线程则执行方法1中6~9即可;
至于分布式集群,是一样的,那台机器负载高你肯定晓得的。