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

arthas

前言

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

下载安装

下载Arthasarthas-boot.jargit

wget https://alibaba.github.io/arthas/arthas-boot.jar

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

[root@izwz94a0v1sz0gk4rezdcbz arthas]# java -jar arthas-boot.jar -h
[INFO] arthas-boot version: 3.1.4
Usage: arthas-boot [-h] [--target-ip <value>] [--telnet-port <value>]
       [--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
       [--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
       [--attach-only] [-c <value>] [-f <value>] [--height <value>] [--width
       <value>] [-v] [--tunnel-server <value>] [--agent-id <value>] [--stat-url
       <value>] [pid]

Bootstrap Arthas

EXAMPLES:
  java -jar arthas-boot.jar <pid>
  java -jar arthas-boot.jar --target-ip 0.0.0.0
  java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
--agent-id bvDOe8XbTM2pQWjF4cfw
  java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'
  java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
  java -jar arthas-boot.jar -f batch.as <pid>
  java -jar arthas-boot.jar --use-version 3.1.4
  java -jar arthas-boot.jar --versions
  java -jar arthas-boot.jar --session-timeout 3600
  java -jar arthas-boot.jar --attach-only
  java -jar arthas-boot.jar --repo-mirror aliyun --use-http
WIKI:
  https://alibaba.github.io/arthas

Options and Arguments:
 -h,--help                      Print usage
    --target-ip <value>         The target jvm listen ip, default 127.0.0.1
    --telnet-port <value>       The target jvm listen telnet port, default 3658
    --http-port <value>         The target jvm listen http port, default 8563
    --session-timeout <value>   The session timeout seconds, default 1800
                                (30min)
    --arthas-home <value>       The arthas home
    --use-version <value>       Use special version arthas
    --repo-mirror <value>       Use special maven repository mirror, value is
                                center/aliyun or http repo url.
    --versions                  List local and remote arthas versions
    --use-http                  Enforce use http to download, default use https
    --attach-only               Attach target process only, do not connect
 -c,--command <value>           Command to execute, multiple commands separated
                                by ;
 -f,--batch-file <value>        The batch file to execute
    --height <value>            arthas-client terminal height
    --width <value>             arthas-client terminal width
 -v,--verbose                   Verbose, print debug info.
    --tunnel-server <value>     The tunnel server url
    --agent-id <value>          The agent id register to tunnel server
    --stat-url <value>          The report stat url
 <pid>                          Target pid

启动

启动arthas以前,先启动一个springboot的应用。该demo在地址https://github.com/yangtao...正则表达式

java -jar ytao-springboot-demo.jar

启动arthas-boot.jar命令spring

java -jar arthas-boot.jar

这里注意须要启动demoarthas使用同一权限用户,不然使用attach机制获取不到进程信息(这里刚使用时没注意,遇到过这个问题)。
例:root用户启动 demou1用户启动arthas时,打印信息Can not find java process. Try to pass <pid> in command line.express

使用另外一user启动

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

日志输出

启动类Bootstrap#main的代码springboot

Bootstrap#main

进程工具类ProcessUtils#select的代码bash

ProcessUtils#select

经过上面也分析到,咱们启动arthas以前,必需要先启动咱们的目标进程,不然arthas可能没法启动。session

使用root用户启动成功界面

arthas启动成功

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

[INFO] arthas home: /root/.arthas/lib/3.1.4/arthas
[INFO] Try to attach process 22005
[INFO] Attach process 22005 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                                

wiki      https://alibaba.github.io/arthas                                      
tutorials https://alibaba.github.io/arthas/arthas-tutorials                     
version   3.1.4                                                                 
pid       17339  
time      2019-10-17 02:29:06

dashboard 数据面板

使用dashboard命令,能够查看线程,内存,GC,以及Runtime信息
dashboard

jad 反编译

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

jad com.ytao.service.UserServiceImpl

jad反编译

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 当前对象

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

watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}"

watch命令的参数和返回值信息

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

watch com.ytao.service.UserServiceImpl getUser "{params[0],returnObj}"

watch命令的具体的入参信息

查看异常信息

watch com.ytao.service.UserServiceImpl getUser "throwExp"

当咱们传入一个参数为-1时,打印出咱们定义的非法参数异常
watch查看异常信息

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

有时咱们排查某个函数,不能立刻获取到函数的信息,arthas给提供的后台异步任务能够帮助咱们记录日志。使用方式和Linux的相似。

watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}" > /log/w.log &

查看异步保存的日志
日志

tt 定位异常调用

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

tt -t com.ytao.service.UserServiceImpl getUser

记录信息
tt信息输出

查看全部记录

tt -l

查看指定函数记录

tt -s 'method.name=="getUser"'

输出信息说明

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

从上面参数中咱们看到1003调用是以抛异常的形式结束,由于tt会记录每次调用的信息,因此咱们能够查看1003的详细信息

tt -i 1003

tt调用详细

trace 查看调用链路

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

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

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

trace com.ytao.service.UserServiceImpl getUser

输出结果
trace输出信息

在实际使用使用排查过程当中,为了减小无用信息的输出,咱们通常会使用#cost过滤耗时不长和jdk自带的函数,能够忽略的调用,减小信息的输出。例如:过滤掉小于1ms的调用

trace com.ytao.service.UserServiceImpl getUser  '#cost > 1'

redefine 实现热部署

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

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

sc -d *UserServiceImpl

classLoaderHash

执行redefine修改的类

redefine -c 1d56ce6a /usr/local/jar/UserServiceImpl.class

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

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




我的博客: https://ytao.top
个人公众号 ytao
个人公众号

相关文章
相关标签/搜索