美文网首页程序员
java应用线上诊断神器--Arthas

java应用线上诊断神器--Arthas

作者: linyb极客之路 | 来源:发表于2020-09-19 19:17 被阅读0次

    前言

    1、什么是Arthas?

    Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱(截止2020.9.19 github star是23K)。通过Arthas我们可以在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。

    2、Arthas有哪些特性

    • 实时查看系统的运行状况
    • 查看函数调用的参数,返回值和异常
    • 代码在线热更新
    • 秒解类冲突问题,定位类加载路径
    • 快速定位应用的热点,生成火焰图
    • 在线诊断,点开网页诊断线上应用

    3、Arthas能帮我们解决什么问题

    当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

    • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
    • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
    • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
    • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
    • 是否有一个全局视角来查看系统的运行状况?
    • 有什么办法可以监控到JVM的实时运行状态?
    • 怎么快速定位应用的热点,生成火焰图?

    4、安装

    下载arthas-boot.jar,然后用java -jar的方式启动:

    curl -O https://arthas.aliyun.com/arthas-boot.jar
    java -jar arthas-boot.jar
    

    本文的示例项目是运行在docker,因此就采用了另外的方式

    docker exec -it  ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
    

    不过在执行的过程中,可能会出现

    /bin/bash: wget: command not found
    

    解决方案如下

    进入容器的/bin/bash
    docker exec -it  ${containerId} /bin/bash
    apt-get update
    apt-get install wget
    

    命令解读

    1、帮助命令相关

    help(查看命令帮助信息

    会列这个命令,源于个人习惯吧。每当学习一个新东西,都会习惯看下帮助,通读一下


    help.png

    当你想了解具体命令的详细用法,以thread为例,输入

    help thread
    
    thread命令详解.png

    就会有详细的thread参数、例子介绍。感觉本文的精华就是这个了,毕竟你想要其他命令,直接

    help 命令
    

    但为了水文,就再介绍几类命令

    2、jvm相关

    dashboard(实时展示当前系统诸如线程、内存占用、GC等信息的面板,默认每个5秒刷新一下面板

    dashboard.png
    :按ctrl+c可以退出面板

    jvm(查看当前JVM信息比如gc回收次数以及耗时等)

    jvm.png

    thread(查看当前线程信息,查看线程的堆栈

    a、 查看当前最忙的前N个线程并打印堆栈

    thread -n 3
    
    thread查看繁忙的线程.png

    上述的命令实现的效果就和我们以往输入

    top -H -p pid
    printf '%x\n'pid
    jstack pid |grep 'nid' -C5 –color
    

    类似

    b、 thread -b, 找出当前阻塞其他线程的线程

    注: 目前只支持找出synchronized关键字阻塞住的线程, 如果是java.util.concurrent.Lock, 目前还不支持

    c、 thread --state ,查看指定状态的线程

    thread根据state查看线程.png

    3、日志相关

    logger(查看logger信息,更新logger level

    3.1、 查看logger信息

    logger.png
    3.2、 动态更新logger level

    修改日志级别步骤

    a、 查找当前类的classloader hashcode

    sc -d com.example.springdemo.user.service.impl.UserServiceImpl | grep classLoaderHash
    

    b、 用OGNL获取logger

    ognl -c 31cefde0 '@com.example.springdemo.user.service.impl.UserServiceImpl@log'
    
    查看日志level.png

    从上图可以知道com.example.springdemo.user.service.impl.UserServiceImpl@log实际使用的是logback。
    可以看到level=null,则说明实际最终的level是从root logger里来的。

    c、 单独设置UserServiceImpl的logger level
    把日志级别变更为warn

    
    ognl -c 31cefde0 '@com.example.springdemo.user.service.impl.UserServiceImpl@log.setLevel(@ch.qos.logback.classic.Level@WARN)'
    
    日志变更.png

    可以看出日志级别已经改为warn

    4、class/classloader相关

    jad(反编译指定已加载类的源码)

    jad反编译.png

    sc(查看JVM已加载的类信息)

    mc(内存编译器,编译.java文件生成.class)

    redefine(加载外部的.class文件,redefine jvm已加载的类)

    为啥介绍这几个,因为这几个组合起来就可以实现动态在线更新代码了。其步骤如下

    a、jad反编译要更新的代码

    
    jad --source-only com.example.springdemo.user.service.impl.UserServiceImpl > /tmp/UserServiceImpl.java
    

    b、sc查找加载要更新代码的ClassLoader

    sc -d com.example.springdemo.user.service.impl.UserServiceImpl | grep classLoaderHash
    

    c、保存好/tmp/UserServiceImpl.java之后,使用mc(Memory Compiler)命令来编译,并且通过--classLoaderClass参数指定ClassLoader

    
    mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserServiceImpl.java -d /tmp
    

    d、使用redefine命令重新加载新编译好的UserServiceImpl.class

    redefine /tmp/com/example/springdemo/user/service/impl/UserServiceImpl.class
    

    5、监控相关

    monitor(方法执行监控,可以监控方法的调用次数、成功次数、失败次数、平均响应时间、失败率)

    注: 这是一个非实时返回命令,统计周期,默认值为120秒

    monitor -c 5 com.example.springdemo.user.service.impl.UserServiceImpl getUserById
    
    monitor.png

    watch(观察指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参)

    watch com.example.springdemo.user.service.impl.UserServiceImpl getUserById "{params,returnObj}" -x 2
    
    watch.png

    watch参数说明


    watch参数说明.png

    trace(方法内部调用路径,并输出方法路径上的每个节点上耗时)

    注: trace 能方便的帮助你定位和发现因 RT 高而导致的性能问题缺陷,但其每次只能跟踪一级方法的调用链路。

    trace com.example.springdemo.user.service.impl.UserServiceImpl getUserById
    
    trace.png

    stack(输出当前方法被调用的调用路径)

    stack com.example.springdemo.user.service.impl.UserServiceImpl getUserById
    
    stack.png

    tt(方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测)

    这个命令的厉害之处在于记录下当前方法的每次调用环境现场,并能进行重放

    tt -t com.example.springdemo.user.service.impl.UserServiceImpl getUserById
    
    tt.png
    tt表格字段说明.png

    b、选择一个index进行重放

    tt -i 1000 -p
    
    tt重放.png
    :这些监控命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 stop 或将增强过的类执行 reset 命令。

    总结

    本文主要介绍Arthas的的一些用法,而这些方法在官网都有很详细的介绍。如果对Arthas感兴趣的朋友的,可以访问官网

    https://arthas.aliyun.com/zh-cn/

    同时也推荐大家访问

    https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn

    里面除了可以在线实操Arthas还可以查看相关用户案例,有助于大家进一步上手Arthas

    参考文档

    https://arthas.aliyun.com/zh-cn/

    相关文章

      网友评论

        本文标题:java应用线上诊断神器--Arthas

        本文链接:https://www.haomeiwen.com/subject/kvzdyktx.html