当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
使用sc命令可以查看指定类的详细信息,包括从哪个jar包加载。
sc *.OfficeListService -d
2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
如果需要确认当前运行的代码,可以通过jad命令,反编译出代码。
jad *.OfficeListService queryOfficeUser
3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
arthas有一系列命令可以对线上代码进行监测。启动监测后,每当方法被调用就会输出监测的相关数据。
watch命令:对指定方法进行数据观测,包括入参、返回值和抛出异常。
watch *.FormController queryApplyDataDetail -f {params,returnObj} -x2
monitor命令:统计指定方法的调用情况,调用次数、成功次数、平均执行时间等
monitor -c 5 *.DashboardMetaController queryList
stack命令:输出指定方法被调用的路径。
stack *.FormDataService queryDataDetail
4. debug时,想在代码中添加日志,但为一行日志代码重新发布太麻烦了。
arthas支持代码热更新,不需要项目重新发布,只修改需要的代码,编译后就可以替换线上正在运行的类。
比如现在线上运行的getVersion接口,现在要修改成返回”arthas_test_version”。
用jad命令反编译出接口所在类的代码,输出成文件。
jad --source-only com.****.system.rest.system.sys.SysConfigController > ~/arthas_test/SysConfigController.java
修改输出的代码。
sc命令+grep命令,找出类的classLoader的哈希值
sc -d com.****.system.rest.system.sys.SysConfigController | grep classLoaderHash
mc命令将修改后的代码编译成class文件。-c后的参数就是找出的classLoader的哈希值。
mc -c 7c81d32b ~/arthas_test/SysConfigController.java -d ~/arthas_test
最后,redefine命令加载新的class文件。
redefine ~/arthas_test/com/****/system/rest/system/sys/SysConfigController.class
再次调用接口,可以看出运行的已经是修改后的代码。
5. 线上遇到某个用户的数据处理有问题,但线上同样无法debug,线下无法重现!
tt命令可以在后台观测并保存指定方法调用时的参数、返回值、异常等信息,并可以用保存的参数再次调用方法。
另外,设置ognl表达式可以让命令在满足条件时才保存记录。例如,出现异常时才保存。
tt -t *.FormController queryById "returnObj.contains(‘\"status\":500‘)" >> tt_logs.txt &
该命令观测FormController的queryById方法,并且只有在返回值字符串中包含”status”:500时才记录。另外,”>>”符号将调用记录重定向到tt_logs.txt文件中,”&”让命令在后台执行,关闭终端也能一直运行。
接下来进行一次出错的调用,可以看出tt记录了这次调用。
根据编号,查看调用的详细信息。
tt -i 1006
另外,可以重放指定编号的调用,显示第二次调用的结果。
tt -i 1006 -p
6. 是否有一个全局视角来查看系统的运行状况?
dashboard命令会显示当前系统的实时数据面板,包括线程、内存、GC、运行时等信息
7. 有什么办法可以监控到JVM的实时运行状态?
除了dashboard命令的数据面板外,还有thread命令可以显示当前线程信息。
可以根据id查看具体线程的堆栈。
thread 187
8. 怎么快速定位应用的热点,生成火焰图?
profiler命令可以在一段时间内对数据采样,生成火焰图。
profiler start --duration 300
该命令对cpu进行300秒的采样。也可以指定对其他数据进行采样。
采样后生成svg或html格式的火焰图。
9. 怎样直接从JVM内查找某个类的实例?
vmtool命令可以查询指定类的内存对象。
vmtool --action getInstances --className java.lang.String -limit 30
该命令查找内存中的String对象,限定前30个。
10. 进行性能调优时需要在代码里添加大量计时器代码,还要重新部署,太麻烦?
trace命令能记录指定方法的调用路径,并统计方法向下一层调用的耗时。
trace *DashboardMetaController queryList
这条监测记录中可以看出queryList方法调用了CommonService:queryPage方法,耗时18ms,占比最大,因此可以trace这个方法,向下深入,最终找出性能瓶颈。