当时产生 CPU 飙升接近 100% 的原因是因为项目中的 websocket 时时断开又重连导致 CPU 飙升接近 100% . 如何排查的呢 是通过日志输出错误信息: 得知 websocket 时时重新
连接的信息, 然后找到原因 解决了.
当然这里幸好能通过日志大致分析出原因 那么我就在思考如果日志没有告诉任何信息 但线上 CPU 还是接近 100% 那么如何排查呢. 所以学习了下排查过程.
通过查阅资料并实践后, 这里总结了两种办法. 第一种博客满天飞的方法 通过 top 命令 第二种非常好用 通过大牛写的脚本排查
一, top 命令排查
1, 命令四部曲
(1) 通过 top 命令, 知道 CPU 最高的进程
top
(2) 具体查看 java 中哪个线程一直在占用 CPU 时间 (这里我的 java 进程号是: 8752)
- #java 进程 ID 进行 CPU 占用排查 (sort -rn 以数值的方式进行逆序排列)
- ps -mp 8752 -o THREAD,tid,time | sort -rn | more
(3) 根据 2 中查找到的 CPU 最高的排序中的结果, 找出几个占用 CPU 时间比较高的 TID, 将线程 ID 转换为 16 进制
printf "%x\n" TID
(4) 再使用 jstack 命名查询是哪个线程
- #8752 是 java 进程 ID,6669 是第三步线程 ID 转换的 16 进制
- jstack 8752 |grep 6669 -A 30
2, 案例
(1) top 命令
(2)ps 命令
(3)printf 命令
(4)jstack 命令
二, show-busy-java-threads.sh 脚本
上面的 4 步虽然能够排查问题, 但总的还是还是太繁琐耗时了, 于是有大神写了个脚本, 在有问题的时候一键定位, 能够妙计找到问题. 这个作者是一个叫淘宝的 oldratlee 同学 https://github.com/oldratlee .
1, 脚本使用说明
怎么使用呢? 可以看作者的 GitHub 地址中的文档说明, 而且里面也有相应脚本: GitHub https://github.com/oldratlee/useful-scripts
我们可以把这个 Git 项目 clone 到 Linux 环境中 (说明: 目前这个脚本只支持 Linux 环境)
Git clone https://github.com/oldratlee/useful-scripts.git #将下面下载到 Linux 环境中.
这里也整理一些该脚本的常用命令
- show-busy-java-threads.sh
- # 从 所有的 Java 进程中找出最消耗 CPU 的线程 (缺省 5 个), 打印出其线程栈.
show-busy-java-threads.sh -c < 要显示的线程栈数 >
show-busy-java-threads.sh -c < 要显示的线程栈数 > -p < 指定的 Java Process>
# -F 选项: 执行 jstack 命令时加上 - F 选项 (强制 jstack), 一般情况不需要使用
show-busy-java-threads.sh -p < 指定的 Java Process> -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 来执行, 即可以解决:
- sudo show-busy-java-threads.sh
2, 案例说明
为了反应真实性, 找了个能让 CPU 飙升 100% 的代码打包成 jar 在线上跑, 这里采用定时任务让它跑起来.
- //java 正则表达式回溯造成 CPU 100%
- @Service
- public class GateTrigger {
- @Scheduled(fixedDelay = 1 * 1000)
- public void startSummary() {
- String[] patternMatch = {"([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)",
- "([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)"};
- List<String> patternList = new ArrayList<String>();
- patternList.add("Avg Volume Units product A + Volume Units product A");
- patternList.add("Avg Volume Units / Volume Units product A");
- patternList.add("Avg retailer On Hand / Volume Units Plan / Store Count");
- patternList.add("Avg Hand Volume Units Plan Store Count");
- patternList.add("1 - Avg merchant Volume Units");
- patternList.add("Total retailer shipment Count");
- for (String s : patternList) {
- for (int i = 0; i < patternMatch.length; i++) {
- Pattern pattern = Pattern.compile(patternMatch[i]);
- Matcher matcher = pattern.matcher(s);
- System.out.println(s);
- //CPU 飙升根源
- if (matcher.matches()) {
- System.out.println("Passed");
- } else
- System.out.println("Failed;");
- }
- }}
- }
(1)top 命令 发现 CPU 的确飙升了
(2) 执行脚本
bash show-busy-java-threads.sh
(3) 看后台运行结果
......
发现一下子就定位问题了, 不得不说缺少很方便, 快捷.
参考
1,Java 死锁排查和 Java CPU 100% 排查的步骤整理 https://www.jianshu.com/p/46d3356c43a7
2, 线上服务 CPU 100%? 一键定位 so easy! https://my.oschina.net/leejun2005/blog/1524687
如果一个人充满快乐, 正面的思想, 那么好的人事物就会和他共鸣, 而且被他吸引过来. 同样, 一个人老带悲伤, 倒霉的事情也会跟过来.
-- 在自己心情低落的时候, 告诫自己不要把负能量带给别人.(大校 10)
来源: https://www.cnblogs.com/qdhxhz/p/9998638.html