用Arthas解决线上正则表达式导致CPU100%的问题

前言

在项目中,我们常常会面临CPU过高或堆内存溢出的问题,解决这类问题通常需要查看线程的堆栈信息。本文将重点介绍两种线程排查工具:jstack和Arthas。当然,Arthas还有许多其他用途,例如在不修改代码的情况下查看方法调用的输入输出参数、异常信息等。最后,我们将引入一个线上的真实案例进行说明。

线程排查工具jstack

jstack介绍

jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

命令格式

常用命令: jstack [-l]

-l 打印关于锁的附加信息

比如:

jps -ml 查看到应用进程id是57,

jstack -l 57 可以查看到当前jvm的线程快照。

jstack -l 57 >jstack.log 生成线程快照到指定文件里

定位占用CPU较高的线程

  1. top查找出哪个进程消耗的cpu高。执行top命令,默认是进程视图,其中PID是进程号

这里我们分析140这个java进程

  1. top中shift+h 或"H"查找出哪个线程消耗的cpu高

先输入top,然后再按shift+h 或"H",此时打开的是线程视图,pid为线程号

这里我们分析502这个线程,并且注意的是,这个线程是属于140这个进程的。

  1. jstack查找这个线程的信息

jstack [进程]|grep -A 10 [线程的16进制]

即: jstack 140 | grep -A 10 0x1f6

-A 10表示查找到所在行的后10行。502用计算器转换为16进制是1f6,注意字母是小写。

结果:

说不定可以一下子定位到出问题的代码。

Arthas

Arthas 简介

Arthas是一款Alibaba开源的Java诊断工具,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

常用命令

dashboard

使用dashboard命令可以显示当前系统的实时数据面板,包括线程信息、JVM内存信息及JVM运行时参数。

thread

查看当前线程信息,查看线程的堆栈,可以找出当前最占CPU的线程。

perl 复制代码
# 打印当前cpu占用率最高的3个线程的堆栈信息
thread -n 3
# 查看ID为1都线程的堆栈信息
thread 1
# 找出当前阻塞其他线程的线程
thread -b
# 查看指定状态的线程
thread -state WAITING

jad

反编译已加载类的源码,觉得线上代码和预期不一致,可以反编译看看。

jad com.yonyou.devcenter.platform.DevCenterBootStrap

使用--source-only参数可以只打印类信息。

jad --source-only com.yonyou.devcenter.platform.DevCenterBootStrap

monitor

实时监控方法执行信息,可以查看方法执行成功此时、失败次数、平均耗时等信息。

monitor -c 5 com.yonyou.devcenter.platform.controller.PluginController search

-c 统计间隔,后面跟数字,代表每多少秒统计一次

watch

方法执行数据观测,可以观察方法执行过程中的参数、返回值和报错信息等。方便在没有日志的情况下快速定位问题。

watch com.yonyou.devcenter.platform.controller.PluginController search '{params,returnObj,throwExp}' -n 5 -x 3

-n 代表捕获结果次数,

-x 代表遍历深度

trace

跟踪某个方法的调用链路,查看耗时情况等

trace com.yonyou.devcenter.platform.controller.PluginController search -n 5 --skipJDKMethod false

-n 代表捕获结果次数

--skipJDKMethod 默认情况下,trace 不会包含 jdk 里的函数调用,如果希望 trace jdk 里的函数,需要显式设置--skipJDKMethod false

真实案例

前一段时间,我们生产上的一个服务出现了cpu达到100%的问题。通过使用Arthas排查分析,最终定位到问题并解决。

现象

运维报该服务的cpu达到了100%

定位

  1. 查看日志,日志报java.lang.OutOfMemoryError: Java heap space,也就是java堆溢出。除此之外,没有其它明显信息。
  2. 使用arthas查看线程信息,输入 thread -n 10,列出10个占用cpu最高的线程堆栈信息。如下图所示,最高的线程cpuUsage=10.59%,紧接着其它的线程的堆栈信息跟这个几乎一样,多次出现"java.util.regex.Pattern$Loop.match"字样,Loop是循环的意思,猜测可能是陷入了死循环。
  3. 网上搜索"java.util.regex.Pattern$Loop.match",发现是正则表达式的一个缺陷,当某些情况下写法不规范并且待匹配的内容很长时,会触发回溯机制,导致了循环的产生。正则表达式有三个模式,默认是贪婪模式,另外两个是独占模式和懒惰模式,在其它两个模式不会有这种问题。
  4. 查看源码,定位到该代码是在一个三方包里,同时追踪到该正则表达式所在的位置,是在一个配置文件里。

解决

解决方法有两种,一个是优化写法,一个是采用其它模式。

ini 复制代码
String regular_1 = "/(([a-z0-9]|[A-Z]|\-)+).html";    //原写法
String regular_2 = "/([a-z0-9A-Z-]+).html";  //优化后的写法
String regular_3 = "/([a-z0-9A-Z-]++).html";   //优化并采用独占模式

通过测试发现,优化写法后速度提高很多,而优化后再采用独占模式,速度更快。最终采用两种方式结合,优化写法同时采用独占模式。最后上线更新,问题解决。

参考文档:

jstack 工具:www.cnblogs.com/snake23/arc...

arthas使用:www.macrozheng.com/project/art...

arthas官网:arthas.aliyun.com/doc/

正则表达式优化:www.jianshu.com/p/f31374611...

相关推荐
喵叔哟9 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟9 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk12 分钟前
maven环境搭建
java·maven
Daniel 大东31 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
wind瑞37 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen38 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)43 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿44 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
修道-032344 分钟前
【JAVA】二、设计模式之策略模式
java·设计模式·策略模式
九圣残炎1 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode