本文总结了一些常见的线上应急现象和对应排查步骤和工具。分享的主要目的是想让对线上问题接触少的同学有个预先认知,免得在遇到实际问题时手忙脚乱。毕竟作者自己也是从手忙脚乱时走过来的。

只不过这里先提示一下。在线上应急过程中要记住,只有一个总体目标:尽快恢复服务,消除影响。不管处于应急的哪个阶段,我们首先必须想到的是恢复问题,恢复问题不一定能够定位问题,也不一定有完美的解决方案,也许是通过经验判断,也许是预设开关等,但都可能让我们达到快速恢复的目的,然后保留部分现场,再去定位问题、解决问题和复盘

在大多数情况下,我们都是先优先恢复服务,保留下当时的异常信息(内存dump、线程dump、gc log等等,在紧急情况下甚至可以不用保留,等到事后去复现),等到服务正常,再去复盘问题。

常见现象:CPU 利用率高/飙升

场景预设:

监控系统突然告警,提示服务器负载异常。

预先说明:

CPU飙升只是一种现象,其中具体的问题可能有很多种,这里只是借这个现象切入。

注:CPU使用率是衡量系统繁忙程度的重要指标。但是CPU使用率的安全阈值是相对的,取决于你的系统的IO密集型还是计算密集型。一般计算密集型应用CPU使用率偏高load偏低,IO密集型相反。

常见原因:

  • 频繁 gc
  • 死循环、线程阻塞、io wait...etc

模拟

这里为了演示,用一个最简单的死循环来模拟CPU飙升的场景,下面是模拟代码,

在一个最简单的SpringBoot Web 项目中增加CpuReaper这个类,

@Componentpublic class CpuReaper {    @PostConstruct    public void cpuReaper() {        int num = 0;        long start = System.currentTimeMillis() / 1000;        while (true) {            num = num + 1;            if (num == Integer.MAX_VALUE) {                System.out.println("reset");                num = 0;            }            if ((System.currentTimeMillis() / 1000) - start > 1000) {                return;            }        }    }}

打包成jar之后,在服务器上运行。java -jar cpu-reaper.jar

(1)第一步:定位出问题的线程

方法 a: 传统的方法

1、top 定位CPU 最高的进程执行top命令,查看所有进程占系统CPU的排序,定位是哪个进程搞的鬼。在本例中就是咱们的java进程。PID那一列就是进程号。

2、top -Hp pid 定位使用 CPU 最高的线程

3、printf '0x%x' tid 线程 id 转化 16 进制

> printf '0x%x' 12817> 0x3211

4、jstack pid | grep tid 找到线程堆栈

> jstack 12816 | grep 0x3211 -A 30

方法 b: show-busy-java-threads

这个脚本来自于github上一个开源项目,项目提供了很多有用的脚本,show-busy-java-threads就是其中的一个。使用这个脚本,可以直接简化方法A中的繁琐步骤。如下,

> wget --no-check-certificate https://raw.github.com/oldratlee/useful-scripts/release-2.x/bin/show-busy-java-threads> chmod +x show-busy-java-threads> ./show-busy-java-threads
show-busy-java-threads# 从所有运行的Java进程中找出最消耗CPU的线程(缺省5个),打印出其线程栈# 缺省会自动从所有的Java进程中找出最消耗CPU的线程,这样用更方便# 当然你可以手动指定要分析的Java进程Id,以保证只会显示你关心的那个Java进程的信息show-busy-java-threads -p show-busy-java-threads -c 

方法 c: arthas thread

阿里开源的arthas现在已经几乎包揽了我们线上排查问题的工作,提供了一个很完整的工具集。在这个场景中,也只需要一个thread -n命令即可。

> curl -O https://arthas.gitee.io/arthas-boot.jar # 下载

后续

通过第一步,找出有问题的代码之后,观察到线程栈之后。我们就要根据具体问题来具体分析。这里举几个例子。

1、情况一:发现使用CPU最高的都是GC 线程。

GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fd99001f800 nid=0x779 runnableGC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fd990021800 nid=0x77a runnable GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fd990023000 nid=0x77b runnable GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fd990025000 nid=0x77c runnabl

2、情况二:发现使用CPU最高的是业务线程

  • io wait

    • 比如此例中,就是因为磁盘空间不够导致的io阻塞
  • 等待内核态锁,如 synchronized
    • jstack -l pid | grep BLOCKED 查看阻塞态线程堆栈
    • dump 线程栈,分析线程持锁情况。
    • arthas提供了thread -b,可以找出当前阻塞其他线程的线程。针对 synchronized 情况

常见现象:频繁 GC

1、 回顾GC流程

在了解下面内容之前,请先花点时间回顾一下GC的整个流程。

接前面的内容,这个情况下,我们自然而然想到去查看gc 的具体情况。

  • 方法a : 查看gc 日志
  • 方法b : jstat -gcutil 进程号 统计间隔毫秒 统计次数(缺省代表一致统计
  • 方法c : 如果所在公司有对应用进行监控的组件当然更方便(比如Prometheus + Grafana)

这里对开启 gc log 进行补充说明。一个常常被讨论的问题(惯性思维)是在生产环境中GC日志是否应该开启。因为它所产生的开销通常都非常有限,因此我的答案是需要开启。但并不一定在启动JVM时就必须指定GC日志参数。

HotSpot JVM有一类特别的参数叫做可管理的参数。对于这些参数,可以在运行时修改他们的值。我们这里所讨论的所有参数以及以“PrintGC”开头的参数都是可管理的参数。这样在任何时候我们都可以开启或是关闭GC日志。比如我们可以使用JDK自带的jinfo工具来设置这些参数,或者是通过JMX客户端调用HotSpotDiagnostic MXBean的setVMOption方法来设置这些参数。

这里再次大赞arthas❤️,它提供的vmoption命令可以直接查看,更新VM诊断相关的参数。

获取到gc日志之后,可以上传到GC easy帮助分析,得到可视化的图表分析结果。

2、GC 原因及定位

prommotion failed

从S区晋升的对象在老年代也放不下导致 FullGC(fgc 回收无效则抛 OOM)。

可能原因:

  • survivor 区太小,对象过早进入老年代查看 SurvivorRatio 参数
  • 大对象分配,没有足够的内存dump 堆,profiler/MAT 分析对象占用情况
  • old 区存在大量对象dump 堆,profiler/MAT 分析对象占用情况

你也可以从full GC 的效果来推断问题,正常情况下,一次full GC应该会回收大量内存,所以 正常的堆内存曲线应该是呈锯齿形。如果你发现full gc 之后堆内存几乎没有下降,那么可以推断:**堆中有大量不能回收的对象且在不停膨胀,使堆的使用占比超过full GC的触发阈值,但又回收不掉,导致full GC一直执行。换句话来说,可能是内存泄露了。

一般来说,GC相关的异常推断都需要涉及到内存分析,使用jmap之类的工具dump出内存快照(或者 Arthas的heapdump)命令,然后使用MAT、JProfiler、JVisualVM等可视化内存分析工具。

至于内存分析之后的步骤,就需要小伙伴们根据具体问题具体分析啦。

六、涉及工具

再说下一些工具。

  • Arthas
  • useful-scripts
  • GC easy
  • Smart Java thread dump analyzer - thread dump analysis in seconds
  • PerfMa - Java虚拟机参数/线程dump/内存dump分析
  • Linux 命令
  • Java N 板斧
  • MAT、JProfiler...等可视化内存分析工具

dump分析工具_Java应用CPU过高,如何排查?参考解决思路和常用工具总结相关推荐

  1. CPU 飙高问题排查和解决方法

    摘要 本文档记录了排查 CPU 飙高问题的处理过程和解决方法,从多个方面进行分析和排查. 问题简述 在一个生产环境中发现 CPU 飙高问题,但是无法确定问题的具体原因. 排查方法 使用 jstack ...

  2. json.tojsonstring 导致cpu飙高_阿里调试神器立功了!进程导致Kubernetes节点CPU飙高的排查与解决...

    来源:https://www.cnblogs.com/maxzhang1985/p/12673160.html 一.发现问题 在一次系统上线后,我们发现某几个节点在长时间运行后会出现CPU持续飙升的问 ...

  3. 4服务器内存和普通内存_Java服务器内存过高CPU过高问题排查

    一.内存过高 1.内存过高一般有两种情况:内存溢出和内存泄漏 (1)内存溢出:程序分配的内存超出物理机的内存大小,导致无法继续分配内存,出现OOM报错 (2)内存泄漏:不再使用的对象一直占据着内存不释 ...

  4. Java服务器内存过高CPU过高问题排查

    Java服务器内存过高&CPU过高问题排查 一.内存过高 1.内存过高一般有两种情况:内存溢出和内存泄漏 (1)内存溢出:程序分配的内存超出物理机的内存大小,导致无法继续分配内存,出现OOM报 ...

  5. MySQL CPU 使用率高的原因和解决方法(来自aliyun官方文档)

    MySQL CPU 使用率高的原因和解决方法 更新时间:2017-03-17 13:25:52   分享: 用户在使用 MySQL 实例时,会遇到 CPU 使用率过高甚至达到 100% 的情况.本文将 ...

  6. java进程CPU占用高如何排查-案例二

    近期项目新版本上线遇到cpu冲高现象,依据之前的经验,把这次排查过程记录下. 这次排查参考了之前记录的经验,还是很有用的:java进程cpu占用高如何排查_停5s的博客-CSDN博客_java进程cp ...

  7. 高级必会,摸鱼必背之CPU过高常见原因与解决

    1.CPU过高常见原因 代码的锅, 比如 :死循环,递归 系统创建了大量线程池.线程池并发执行导致CPU过高 JVM在频繁执行full gc 2.频繁full gc原因 JVM内存配置不合理,导致新生 ...

  8. 西湖大学鞠峰组:环境宏病毒组学分析思路与常用工具

    环境宏病毒组学分析思路与常用工具 袁凌1, 2,倪艳4,鞠峰1, 2, 3 * 1 浙江省海岸带环境与资源研究重点实验室,工学院, 西湖大学, 杭州, 浙江 2  前沿技术研究所, 浙江西湖高等研究院 ...

  9. MySQL CPU 使用率高的原因和解决方法

    MySQL CPU 使用率高的原因和解决方法 参考文章: (1)MySQL CPU 使用率高的原因和解决方法 (2)https://www.cnblogs.com/wyy123/p/9258513.h ...

最新文章

  1. IT项目经理学习-德鲁克时间管理
  2. python 重定向 ctf_3.CTF——python利用工具
  3. Android插件化开发之动态加载基础之ClassLoader工作机制
  4. 加载tf模型 正确率很低_深度学习模型训练全流程!
  5. css3浏览,css3支持哪些浏览器?
  6. 四.开发记录之ubuntu系统安装ROS和开发环境
  7. 单片机定时器中断原理
  8. ajax常见的面试题
  9. echarts 折线图数据太多会导致卡顿_重新定义数据图表,还有比这个更厉害的吗?...
  10. Android项目实战登录注册
  11. 7.20-7.24(2)
  12. BZOJ2287 【POJ Challenge】消失之物 动态规划 分治
  13. Apache HttpClient 客户端使用详解
  14. 计算机办公软件考证教学总结,考证经历——办公软件的套路
  15. Mac WinToGO
  16. Oracle锁表解决方法
  17. 基于社会工程学的网络攻击手段分析
  18. Jfinal-Controller层注入Service空指针异常
  19. etho失败,无法上网的解决方法
  20. 静态代理之AspectJ编译织入

热门文章

  1. CentOS 7 : Docker私有仓库搭建和使用
  2. 利用 Charles Proxy 下载旧版本 iOS App
  3. wampserver 虚拟主机
  4. Struts2的工作原理及工作流程
  5. 十天学Linux内核之第七天---电源开和关时都发生了什么
  6. case when then的用法
  7. 改造MUC实现Openfire群
  8. Android——Ubuntu android NDK 配置
  9. 数据结构之顺序表(一)
  10. [python作业AI毕业设计博客]比Selenium IDE更好用的录制工具: Katalon Recorder