用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...

相关推荐
李少兄8 分钟前
如何从远程Maven仓库下载JAR包并手动放置到本地仓库
java·maven·jar
CodeMartain9 分钟前
stream流的toMap
java·开发语言
ling1s20 分钟前
C#核心(18)面向对象多态vob
java·开发语言·c#
sin220122 分钟前
idea创建springBoot的五种方式
java·spring boot·intellij-idea
皓木.29 分钟前
苍穹外卖——准备工作
java·数据库·mybatis
愤怒的代码43 分钟前
Spring Boot对访问密钥加密解密——RSA
java·spring boot·后端
美美的海顿44 分钟前
springboot基于Java的校园导航微信小程序的设计与实现
java·数据库·spring boot·后端·spring·微信小程序·毕业设计
愤怒的代码1 小时前
Spring Boot中幂等性的应用
java·spring boot·后端
silver6871 小时前
JAVA8 Stream API 使用详解
java
武子康1 小时前
大数据-259 离线数仓 - Griffin架构 修改配置 pom.xml sparkProperties 编译启动
xml·java·大数据·hive·hadoop·架构