引言

针对Java应用在生产环境下出现的问题,通常开发者想通过远程debug的方式来排查问题是不可行的。一是私有云的客户系统无法连接去调试,连接上也会由于debug断点导致所有业务请求被暂停。二是需要额外添加日志来部署到线上观察,效率非常低下。当然,线上问题远不止这些,还需要结合Linux和JVM指令来监控系统整体运行指标。

因此,为了能够解决上述常规排查手段的弊端,这里介绍一款开源的Java诊断工具Arthas,该工具提供了jvm整体监控、线程堆栈、类加载器检查、方法级别的监控等丰富的操作,来定位在线Java应用问题。另外,值得注意的是由于该工具采用字节码植入方式,对于应用的运行性能和安全性需要考虑一下。

使用说明

安装

下载arthas-packing-xxx-bin.zip直接解压,进行本地安装,默认安装在user.home的用户目录下面。

  • 启动:
    执行java –jar arthas-boot.jar,进入交互式命令行界面,选择需要监控的java应用进程号,控制台打印attach process xxx success 表示连接成功,输入help显示指令帮助说明,表示可以开始正式使用了。注意:如果没有第一步的本地安装,执行启动命令,会访问网络下载安装,内网用户将会无法使用。
  • 卸载:
    标准安装的话,安装目录在~/.arthas,执行rm –rf ~/.arthas即可。否则直接删除当前所在目录的sh和jar。

使用

  • 基础命令
    help——查看命令帮助信息
    cls——清空当前屏幕区域
    session——查看当前会话的信息
    reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
    version——输出当前目标 Java 进程所加载的 Arthas 版本号
    history——打印命令历史
    quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
    shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
    keymap——Arthas快捷键列表及自定义快捷键

  • jvm相关
    dashboard——当前系统的实时数据面板
    thread——查看当前 JVM 的线程堆栈信息
    jvm——查看当前 JVM 的信息
    sysprop——查看和修改JVM的系统属性
    sysenv——查看JVM的环境变量
    getstatic——查看类的静态属性

  • class/classloader相关
    sc——查看JVM已加载的类信息
    sm——查看已加载类的方法信息
    dump——dump 已加载类的 byte code 到特定目录
    redefine——加载外部的.class文件,redefine到JVM里
    jad——反编译指定已加载类的源码
    classloader——查看classloader的继承树,urls,类加载信息,使用classloader去getResource

  • monitor/watch/trace相关
    请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 shutdown 或将增强过的类执行 reset 命令。
    monitor——方法执行监控
    watch——方法执行数据观测
    trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
    stack——输出当前方法被调用的调用路径
    tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

  • options
    options——查看或设置Arthas全局开关

  • 管道
    Arthas支持使用管道对上述命令的结果进行进一步的处理,如sm org.apache.log4j.Logger | grep <init>
    grep——搜索满足条件的结果
    plaintext——将命令的结果去除颜色
    wc——按行统计输出结果

  • 后台异步任务
    当线上出现偶发的问题,比如需要watch某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了
    使用 > 将结果重写向到日志文件,使用 & 指定命令是后台运行,session断开不影响任务执行(生命周期默认为1天)
    jobs——列出所有job
    kill——强制终止任务
    fg——将暂停的任务拉到前台执行
    bg——将暂停的任务放到后台执行

  • ognl相关官方文档
    一般配合watch指令使用,其中的express、condition-express 采用ognl表达式
    用于监控成员方法和类级别静态方法的入参(params)、返回值(returnObj)、抛出异常(throwExp)等。示例:

    执行一次查看Test类的test方法的第一个参数(list)的第一个对象(pojo)中的age属性
    watch Test test params[0].get(0).age -n 1
    //还可以通过下标的方式访问params[0][0][“age”] ,这个写法等效于params[0][0].age

    执行一次查看Test类的test方法的第一个参数(list)的所有对象(pojo)中age>5的姓名
    watch Test test "params[0].{? #this.age > 5}.{name}" -n 1
    //那如果要找到第一个age大于5的Pojo的name,可以用^ 或$ 来进行第一个或最后一个的匹配

    执行一次查看Test类中的静态变量m
    watch Test test '@Test@m' -n 1

应用场景

  • 定位内存泄露、资源未释放等问题:
    查看系统整体运行情况,包括线程概览、堆与非堆内存使用、GC次数与耗时、操作系统等信息
    dashboard –i 10000 //十秒钟刷新一次

  • 定位有问题的处理逻辑
    查看前3个占用cpu比较高的线程堆栈
    thread –n 3

  • 定位jar包冲突的问题
    查看使用的类所在的jar以及类加载器
    sc –d 全路径类名`

  • 性能测试,统计方法的执行平均耗时、成功/失败次数统计
    确认要统计的业务类中的方法名
    monitor 全路径类名 方法名 -c 1

  • 定位耗时的业务逻辑处理,从而有针对性地优化
    通过trace方法查看指定方法的调用堆栈和最耗时的方法
    trace全路径类名 方法名

  • 查看方法的入参和返回值,确认业务逻辑处理的正确性
    通过watch和ognl表达式来检测结果
    watch 全路径类名 方法名 ‘params[0] + “, ”+ returnObj’

总结

以上介绍了Arthas是如何解决以往线上Java应用程序诊断的不足带来的问题,用好这些命令还需要多多结合实际问题去实践。最重要的,还是需要具备程序运行诊断的思路,工具只是辅助我们采集想要的信息,并且需要具备从这些信息中分析出问题,给出解决方案的能力。