Arthas中如何使用watch命令,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
创新互联是一家集网站建设,汾西企业网站建设,汾西品牌网站建设,网站定制,汾西网站建设报价,网络营销,网络优化,汾西网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
Arthas 官网是这么介绍自己的:
Arthas 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。 当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决:
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
是否有一个全局视角来查看系统的运行状况?
有什么办法可以监控到 JVM 的实时运行状态?
怎么快速定位应用的热点,生成火焰图?
方式一:通过 Cloud Toolkit 实现 Arthas 一键远程诊断
Cloud Toolkit 是阿里云发布的免费本地 IDE 插件,帮助开发者更高效地开发、测试、诊断并部署应用。通过插件,可以将本地应用一键部署到任意服务器,甚至云端(ECS、EDAS、ACK、ACR 和 小程序云等);并且还内置了 Arthas 诊断、Dubbo工具、Terminal 终端、文件上传、函数计算 和 MySQL 执行器等工具。不仅仅有 IntelliJ IDEA 主流版本,还有 Eclipse、Pycharm、Maven 等其他版本。
推荐使用 IDEA 插件下载 Cloud Toolkit 来使用 Arthas:http://t.tb.cn/2A5CbHWveOXzI7sFakaCw8
方式二:直接下载
地址:https://github.com/alibaba/arthas。
curl -O https://alibaba.github.io/arthas/arthas-boot.jar && java -Dfile.encoding=UTF-8 -jar arthas-boot.jar 复制代码
稍微解释一下上面这条 shell 命令。命令分为两部分,&&
之前的部分是下载 Arthas,之后的部分是启动 Arthas。
你可能会疑惑下载文件为什么不用 wget
而是用 curl
?这是因为有些服务器是没有预装 wget
的,但是基本都预装了 curl
。如果你的服务器预装了 wget
的话完全可以把 'curl' 改成 wget
。
如果使用 wget 的话命令可以改成:
# wget 版命令 wget https://alibaba.github.io/arthas/arthas-boot.jar && java -Dfile.encoding=UTF-8 -jar arthas-boot.jar 复制代码
另外一个需要解释的点是 -Dfile.encoding=UTF-8
,这个 Java 设置是为了让 Arthas 输出中文的时候不会乱码,这一点可以看一下我以前的文章 由 Arthas 中文乱码引发的 Java 默认编码思考。
watch
让你能方便地观察到指定方法的调用情况。能观察到的范围为:返回值
、抛出异常
、入参
(还能观察执行函数的对象本身,不知道为什么官方介绍的时候没说这个」,通过编写 OGNL 表达式进行对应变量的查看。
# watch -h # USAGE watch [-b] [-e] [-x] [-f] [-h] [-n ] [-E] [-M ] [-s] class-pattern method-pattern express [condition-express] 复制代码
returnObj
使用方式看着复杂,其实很简单。来个最简单的示例: 假设我们要观察下面这段代码中字符串的 contains
方法。
public class App { public static void main(String[] args) throws IOException { String hello = "Hello Arthas"; while (true) { boolean contains = StringUtils.contains(hello, "Arthas"); System.out.println(contains); } } } 复制代码
可以使用如下语句:
## 观察 contains 返回结果 [arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains returnObj -n 3 # Press Q or Ctrl+C to abort. # Affect(class-cnt:1 , method-cnt:2) cost in 68 ms. # ts=2020-05-02 16:46:04; [cost=2.424254ms] result=@Boolean[true] # ts=2020-05-02 16:46:05; [cost=0.21033ms] result=@Boolean[true] # ts=2020-05-02 16:46:06; [cost=0.165514ms] result=@Boolean[true] 复制代码
-n 3
表示只执行三次,这参数挺常用,不然很容易被输出刷屏。
condition-express
显然,真实的案例肯定不会如上面的示例那么简单。 真实的服务代码中,肯定不止一个地方调用了 String 的 contains
方法。我们需要把无关的调用过滤掉。
## 观察 contains 返回结果,并且过滤掉无关调用 [arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains returnObj 'params[1]=="Arthas"' # Press Q or Ctrl+C to abort. # Affect(class-cnt:1 , method-cnt:2) cost in 29 ms. # ts=2020-05-02 16:48:50; [cost=0.331109ms] result=@Boolean[true] # ts=2020-05-02 16:48:51; [cost=0.175224ms] result=@Boolean[true] # ts=2020-05-02 16:48:52; [cost=0.138984ms] result=@Boolean[true] 复制代码
入参是一个很容易把不同调用区分开的方法,通过 params[1]=="Arthas"
这个 condition-express
,我们可以只保留第二个入参是 Arthas
的函数调用。
[arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]=="Arthas"' # Press Q or Ctrl+C to abort. # Affect(class-cnt:1 , method-cnt:2) cost in 33 ms. # ts=2020-05-02 16:51:27; [cost=0.507486ms] result=@ArrayList[ # @Object[][isEmpty=false;size=2], # @Boolean[true], # ] 复制代码
通过 {}
把字段包起来,可以同时观察想观察的字段。可以注意到一个点,params
是一个数组,但是打印 params
的时候并没有把具体内容打印出来,这个时候可以使用 -x 2
来指定打印对象的属性遍历深度。
arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]=="Arthas"' -x 2 # Press Q or Ctrl+C to abort. # Affect(class-cnt:1 , method-cnt:2) cost in 35 ms. # ts=2020-05-02 16:51:33; [cost=0.391218ms] result=@ArrayList[ # @Object[][ # @String[Hello Arthas], # @String[Arthas], # ], # @Boolean[true], # ] 复制代码
在陌陌做动态推荐开发的时候,测试时经常会遇到查看某个用户是否开启了相应的业务开关,经常就会需要查看某个实验开关是否开启。
## 查看陌陌用户 1234567 是否开启 ElasticSearch 开关 watch com.momo.Experiment enableElasticSearch returnObj 'target.momoId=="1234567"' # ts=2020-05-02 20:09:46; [cost=24.443527ms] result=@Boolean[true] 复制代码
我还经常会根据入参的陌陌用户 id 进行判断,查看返回结果或者异常:
## 查看 MorecControlFlow 类的 process 方法返回结果 ## process 方法第一个参数的 momoId 属性值为 “123454567” 才生效 ## 类路径和陌陌号都非真实数据 watch com.momo.MorecControlFlow process returnObj 'params[0].momoId=="123454567"' # ts=2019-03-18 21:09:46; [cost=264.434972ms] result=@Boolean[true] ## 查看 IMorecShuffler 类的 shuffle 抛的异常 ## process 方法第一个参数的 momoId 属性值为 “123454567” 才生效 watch com.momo.plugins.shuffler.IMorecShuffler shuffle throwExp 'params[0].morecRequest.momoId=="123454567"' # ts=2019-03-27 20:54:29; [cost=46.642339ms] result=java.lang.IndexOutOfBoundsException: Index: 12, Size: 11 at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:665) at java.util.ArrayList.add(ArrayList.java:477) at com.momo.plugin.shuffler.RoomShuffler.shuffle(RoomShuffler:45)
看完上述内容,你们掌握Arthas中如何使用watch命令的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!