一、序言
通常,本地开发环境无法访问生产环境。在实际工作中,我们会经常遇到在客户现场出现各种奇怪的问题,想要查看具体某个具体的对象,可能要打镜像,还要走银行内部的流程,整体很耗费时间,而且有时候还不能达到目的。现在我们采用k8s云原生进行开发和部署,容器内部调试会更加麻烦。
其次,遇到问题可以在测试环境或者预生产环境中复现问题。但是,某些问题无法在不同的环境中轻松复现,因为一旦 JVM 重新启动,它可能无法复现,甚至在重新启动后就消失了。
Arthas旨在解决这些问题,有利于我们去在线解决生产问题,无需JVM重启,无需代码更改。而且Arthas是通过命令行交互的,作为观察者永远不会暂停正在运行的线程。
Arthas官网的地址:https://arthas.aliyun.com/
二、常用命令
2.1 jvm
命令详情:查看当前的JVM的信息
其中DEADLOCK-COUNT用来记录当前死锁的线程数,可以帮助我们去观察JVM的一些信息。
2.2 memory
命令详情:查看当前JVM的内存信息,可以帮助我们去调整内存参数
2.3 thread
命令详情:查看当前线程信息以及线程的堆栈
thread -n N
打印当前最忙的N个线程并打印堆栈信息
thread -b
可以找出当前阻塞其他线程的线程
thread --state waiting
查看指定状态的线程
2.4 jad
命令详情:反编译指定的已加载类的源码
2.5 mc
命令详情:内存编译器,可以用来加载编译好的class文件
2.6 readfine
命令详情:加载外部的class文件
2.7 sc
命令详情:搜索已经加载到JVM中的class信息
2.8 trace
命令详情:方法内部调用路径,并输出方法路径上的每个节点上耗时,性能调优的时候很有用。
2.9 watch
命令详情:观察指定方法的调用情况,想查看一个对象在内存的具体使用情况,可以找到对应的方法,使用watch便可以观察。
watch参数中支持表达式,默认是params、target、returnObj,如果只是想观察参数和返回值,可以使用params、returnObj;也可以指定是在函数调用之前、函数异常之后、函数返回之后以及函数结束之后(正常返回和异常)观察;可以直接用f,上面的例子其实就是在函数结束之后观察IpushClientInfo对应的status状态。
2.10 stop
命令详情:关闭 Arthas服务端,退出所有Arthas客户端,用redefine 重新加载的类不会被重置
三、集成与实践
3.1 docker集成
目前arthas集成到了jdk的基础镜像,拿打包目录的基础镜像部署,默认就会携带arthas,这样无须改动到原有k8s的编排文件。
FROM openjdk:8-jdk-oracle
# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
WORKDIR /home/icc/
3.2 使用方式
Arthas存在的目录是在/opt/arthas,进入该目录,运行 java -jar arthas-boot.java 便可启动Arthas,跟在虚机上的操作是一样的。
3.3 在线修改代码
背景:存在一个业务场景,消息下发的时候会先判断厂商的状态进而选择通道下发,测试反馈不生效。本地修改部分代码后,需要验证,但自己搭建一套环境又比较麻烦且费时,这时候就可以用Arthas的在线代码修改去验证。
首先使用sc命令查看指定类型加载信息,找到对应的class info,记录下对应的classLoaderHash值
用jad命令进行反编译,–source后面携带的就是对应的class信息,反编译到tmp目录
编辑对应的Java文件,在指定地方加上我们的代码
保存后使用mc内存编译器编译代码。-c指定类加载器的hash值,即sc命令看到的classLoaderHash,-d是指定输出的目录,切换到tmp可以看到编译后的class文件
使用readfine命令,重新加载编译后的class文件
重新验证对应功能,消息下发成功了。结果说明我们修改的代码是正确的,也说明Arthas在线修改代码已经生效了。