23

Java 诊断利器 Arthas 优雅排查生产环境

 4 years ago
source link: https://mp.weixin.qq.com/s/Qb0jGy6xhNqN5CFIGFfKNQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

N36r6jv.jpg!web

前言

Arthas 是Alibaba开源的Java诊断工具。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。对分秒必争的线上异常, Arthas 可帮助我们快速诊断相关问题。

下载安装

下载 Arthasarthas-boot.jar

下载 arthas 之后,先来了解帮助信息,可以通过 java-jar arthas-boot.jar-h 命令查看,这里给出了一些例子和参数说明

启动

启动 arthas 之前,先启动一个 springboot 的应用。该 demo 在地址 https://github.com/yangtao9502/ytao-springboot-demo

启动 arthas-boot.jar 命令

这里注意需要启动 demoarthas 使用同一权限用户,否则使用attach机制获取不到进程信息(这里刚使用时没注意,遇到过这个问题)。例: root 用户启动 demou1 用户启动 arthas 时,打印信息 Cannotfind java process.Trytopass<pid>incommand line. Fze6bee.png!web

查看源码,在获取进程之后,添加日志输出。结果为空,返回 -1 ,判断结果小于 0 时,直接退出。 u6vQRfM.png!web

启动类 Bootstrap#main 的代码 6fEvUzQ.png!web

进程工具类 ProcessUtils#select 的代码 BJvUVnm.png!web

通过上面也分析到,我们启动 arthas 之前,必须要先启动我们的目标进程,否则 arthas 可能无法启动。

使用 root 用户启动成功界面 Nb2qyyA.png!web

选择java进程,这里我们的 ytao-springboot-demo 是 1,选择后会有连接信息

dashboard 数据面板

使用 dashboard 命令,可以查看线程,内存,GC,以及Runtime信息 uIZb6fV.jpg!web

jad 反编译

有时我们会遇到线上代码运行结果不是我们期望的结果,有种情况就是线上代码不是我们想要的版本,但是要查看的话,需要下载后再进行反编译。这时 arthasjad 可以帮助我们线上进行即时反编译,确认代码是否符合我们的版本。

ZRRVBv3.png!web

watch 函数执行信息

使用 watch 命令可以查看函数的执行信息。 watch 的参数列表(来自官网)

参数 参数说明 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 express 观察表达式 condition-express 条件表达式 [b] 在方法调用之前观察 [e] 在方法异常之后观察 [s] 在方法返回之后观察 [f] 在方法结束之后(正常返回和异常返回)观察 [E] 开启正则表达式匹配,默认为通配符匹配 [x:] 指定输出结果的属性遍历深度,默认为 1

当我们遇到线上数据 bug 时,我们一般处理的手段就是开发环境模拟线上数据,从生产日志中查找线索,再或者远程 debug 。以上不管哪种排查手段,相对都是比较麻烦。这时Arthas的 watch 可以帮助我们查看实时的代码执行情况。使用观察表达式可以查看函数的 参数 , 返回值 , 异常信息 。观察表达式主要由 OGNL 表达式组成,所以可以编写 OGNL 表达式来执行。

观察表达式的变量

变量 变量说明 params 函数的入参 returnObj 函数的返回值 throwExp 异常信息 target 当前对象

查看一个函数的入参和返回值

IjqYZru.png!web

打印信息 isEmpty=false;size=1 可以看到参数为非空,参数数量为一个。查看具体入参信息

i6BfAnB.png!web

查看异常信息

当我们传入一个参数为 -1 时,打印出我们定义的非法参数异常 3MnQZrI.png!web

watch 除了观察表达式外,还能使用 条件表达式 ,以及 观察事件点注意 使用观察事件点时,有些观察表达式的变量不一定存在,比如使用 -b 时,返回值和异常信息都为空。 QvENRvz.png!web

有时我们排查某个函数,不能马上获取到函数的信息, arthas 给提供的 后台异步任务 可以帮助我们记录日志。使用方式和Linux的类似。

查看异步保存的日志 UbeeEf3.png!web

tt 定位异常调用

上面所介绍的 watch 可以排查函数的调用情况,比较适用在已知当次调用可能存在的情况后,查看信息。如果一个函数调用n次后,有几次为执行异常,我们要去找出这些异常的调用,在 watch 中排查就不怎么方便了。使用 tt 命令可以较方便查看异常的调用及信息。对 com.ytao.service.UserServiceImpl#getUser 的函数查看, -t 是每次调用该函数都会记录

记录信息 e222QbR.png!web

查看所有记录

查看指定函数记录

输出信息说明

表格字段 字段解释 INDEX 时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。 TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间 COST(ms) 方法执行的耗时 IS-RET 方法是否以正常返回的形式结束 IS-EXP 方法是否以抛异常的形式结束 OBJECT 执行对象的hashCode(),注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体 CLASS 执行的类名 METHOD 执行的方法名

从上面参数中我们看到 1003 调用是以抛异常的形式结束,因为 tt 会记录每次调用的信息,所以我们可以查看 1003 的详细信息

EVnAFzm.png!web

trace 查看调用链路

我们常会遇到调用某个api时rt过长,我们就要找出调用链上的某个或几个函数进行优化,我们通常定位几个可能的锚点,打印各个锚点间的rt。或者从日志中找出日志打印的时间点计算出时间差,不管使用哪种方法都比较繁琐。当使用 arthastrace 命令可以轻松的完成我们的需求。 trace 参数说明

参数 参数说明 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 condition-express 条件表达式 [E] 开启正则表达式匹配,默认为通配符匹配 [n:] 命令执行次数 #cost 方法执行耗时

使用 trace 输出 com.ytao.controller.UserController#getUser 的信息

输出结果

在实际使用使用排查过程中,为了减少无用信息的输出,我们一般会使用 #cost 过滤耗时不长和jdk自带的函数,可以忽略的调用,减少信息的输出。例如:过滤掉小于 1ms 的调用

redefine 实现热部署

当我们查找出bug,想要快速上线拯救苍生的时候, Arthas 为我们准备了 redefine 命令来实现热更新。尽管现在都在倡导 jad / mc / redefine热更 一条龙,但是线上代码建议本地编译好后再进行替换,避免手误操作。首先先在 UserServiceImpl 中添加一行代码 YNNjA32.png!web

获取 classLoaderHash ,通过 sc 命令获取类的信息

z2aqaq7.png!web

执行 redefine 修改的类

通过打印的信息验证是否更新 UserServiceImpl

Arthas 的使用,除了上文中所讲解到的,还有一些其他的诊断功能,这只是我个人使用的方法。但是使用该类工具一定要有套组合拳,对排查问题过程中,遇到问题有对应的排查手段,并非盲目排查。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK