Arthas分享简述

前言

当你兴冲冲地开始运行自己的 Java 项目时,你是否遇到过如下问题:

    1.程序在稳定运行了,可是实现的功能点了没反应。

    2.为了修复 Bug 而上线的新版本,上线后发现 Bug 依然在,却想不通哪里有问题?

    3.想到可能出现问题的地方,却发现那里没打日志,没法在运行中看到问题,只能加了日志输出重新打包——部署——上线

    4.程序功能正常了,可是为啥响应时间这么慢,在哪里出现了问题?

    5.程序不但稳定运行,而且功能完美,但跑了几天或者几周过后,发现响应速度变慢了,是不是内存泄漏了?

以前,你碰到这些问题,解决的办法大多是,修改代码,重新上线。但是在目前公司里,上线的流程是非常繁琐的,如果为了多加一行日志而重新发布版本,无疑是非常折腾人的。

现在,我们有了更为优雅的线上调试方法 - 来自阿里巴巴开源的 Arthas。

Arthas是Alibaba开源的Java诊断工具,当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

    1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

    2.我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

    3.遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?

    4.线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

    5.是否有一个全局视角来查看系统的运行状况?

    6.有什么办法可以监控到JVM的实时运行状态?

    7.怎么快速定位应用的热点,生成火焰图?

在本篇文章中,你能够了解:

    1.Arthas 使用实例:帮助你快速让你上手,拯救你的低效率 Debug

    2.使用 Arthas 解决具体问题:看一下 Arthas 帮我拯救了多少时间

    3.原理浅谈:莫在浮沙筑高阁!你需要大概了解下 Arthas 的原理

Arhas 绝对是你提升效率的利器,适合各种阶段的开发者!


线上 Debug 神器 Arthas

Arthas 使用实例

命令的详细文档请参考:alibaba.github.io/arthas/comm…

快速安装

你只需要两行命令:

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

java -jar arthas-boot.jar

 启动arthas

在命令行下面执行(使用和目标进程一致的用户启动,否则可能attach失败):

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

java -jar arthas-boot.jar

启动 arthas

基本使用

Arthas 有如下功能:

Arthas 基础命令

"上帝视角"指令:dashboard

当前系统的实时数据面板,按 ctrl+c 退出。

当运行在Ali-tomcat时,会显示当前tomcat的实时信息,如HTTP请求的qps, rt, 错误数, 线程池信息等等。

dashboard指令

线程调试相关指令:thread

    1. thread -n x :一键展示当前最忙的前X个线程并打印堆栈

    2. thread id :显示指定线程的运行堆栈

    3. thread -b :找出当前阻塞其他线程的线程

    4.thread -i x :指定采样时间间隔

    5.thread --state x :查看指定状态的线程

jvm监控相关指令:jvm    sysprop    sysenv     vmoption

    1.jvm: 查看当前JVM信息

        THREAD相关

        COUNT: JVM当前活跃的线程数

        DAEMON-COUNT: JVM当前活跃的守护线程数

        PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数

        STARTED-COUNT: 从JVM启动开始总共启动过的线程次数

        DEADLOCK-COUNT: JVM当前死锁的线程数

2.sysprop: 查看当前JVM的系统属性

        查看单个属性

            sysprop java.version

        修改单个属性

            sysprop user.country CN

3.sysenv: 查看当前JVM的环境属性

        查看单个环境变量

            $ sysenv USER

            USER=admin

4.vmoption: 查看,更新VM诊断相关的参数

        查看指定的option

            vmoption PrintGCDetails

        更新指定的option

            vmoption PrintGCDetailstrue


类加载问题相关指令:  sc  sm   

    1.sc: 查看JVM已加载的类信息

    通过 SC 我们可以看到我们这个类的详细信息,包括是从哪个 jar 包读取的,他是不是接口/枚举类等,甚至包括他是从哪个类加载器加载的。

sc查看类信息

SC 也可以查看已加载的类,帮助你看是否有没有纳入进来的类,尤其是在 Spring 中,可以判断的你的依赖有没有正确的进来。

sc查看已加载的类

    2.sm: 查看已加载类的方法信息

        这个命令能搜索出所有已经加载了 Class 信息的方法信息。

        sm 命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。

方法运行相关指令:monitor   watch   trace   stack   

    1.monitor:方法执行监控

        monitor 命令是一个非实时返回命令.

        实时返回命令是输入之后立即返回,而非实时返回的命令,则是不断的等待目标 Java 进程返回信息,直到用户输入 Ctrl+C 为止。

        服务端是以任务的形式在后台跑任务,植入的代码随着任务的中止而不会被执行,所以任务关闭后,不会对原有性能产生太大影响,而且原则上,任何Arthas命令不会引起原有业务逻辑的改变。

        计算条件表达式过滤统计结果(方法执行完毕之后):

        monitor -c 5 demo.MathGame primeFactors "params[0] <= 2"

        计算条件表达式过滤统计结果(方法执行完毕之前):

        monitor -b -c 5 com.test.testes.MathGame primeFactors"params[0] <= 2"

    2.watch:方法执行数据观测

        你可以通过 watch 指令,来监控某个类,监控后,运行下你的功能,复现下场景,arthas 会提供给你具体的出参和入参,帮助你排查故障。

        特别说明

            1.watch 命令定义了4个观察事件点,即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后

            2.4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出

            3.这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参

            4.当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在

        观察方法出参和返回值:

        watch demo.MathGame primeFactors "{params,returnObj}" -x 2

        观察方法入参:

        watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b

        同时观察方法调用前和方法返回后:

        watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2

        调整-x的值,观察具体的方法参数值:

        watch demo.MathGame primeFactors "{params,target}" -x 3

        条件表达式:

        watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"

        观察异常信息:

        watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2

        按照耗时进行过滤:

        watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2

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

        这个指令对于优化代码非常的有用,可以看出具体每个方法执行的时间,如果是 for 循环等重复语句,还能看出 n 次循环中的最大耗时,最小耗时,和平均耗时。

        据调用耗时过滤:

        trace demo.MathGame run '#cost > 10'

    4.stack:输出当前方法被调用的调用路径

        很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。

        据条件表达式来过滤:

        stack demo.MathGame primeFactors 'params[0]<0' -n 2

        据执行时间来过滤:

        stack demo.MathGame primeFactors '#cost>5'

强大的 ognl 表达式:

    众所周知,一般来说,表达式都是调试工具里最强的指令。

    在 Arthas 中你可以利用 ognl 表达式语言做很多事,比如执行某个方法,获取某个信息,甚至进行修改。


使用 Arthas 解决具体问题



原理浅谈

    启动:

    使用了阿里开源的组件 cli,对参数进行了解析:com.taobao.arthas.boot.Bootstrap

    在传入参数中没有 pid,则会调用本地 jps 命令,列出 java 进程。

进入主逻辑,会在用户目录下建立 .arthas 目录,同时下载 arthas-core 和 arthas-agent 等 lib 文件,最后启动客户端和服务端。

通过反射的方式来启动字符客户端。

    服务端——前置准备

        看服务端启动命令可以知道 从 arthas-core.jar开始启动,arthas-core 的 pom.xml 文件里面指定了 mainClass 为 com.taobao.arthas.core.Arthas,使得程序启动的时候从该类的 main 方法开始运行。

        首先解析入参,生成 com.taobao.arthas.core.config.Configure 类,包含了相关配置信息;

        使用 jdk-tools 里面的 VirtualMachine.loadAgent,其中第一个参数为 agent 路径, 第二个参数向 jar 包中的 agentmain() 方法传递参数(此处为 agent-core.jar 包路径和 config 序列化之后的字符串),加载 arthas-agent.jar 包;

        运行 arthas-agent.jar 包,指定了 Agent-Class为com.taobao.arthas.agent.AgentBootstrap。

    服务端——监听客户端请求

        如果是 exit,logout,quit,jobs,fg,bg,kill 等直接执行;

        如果是其他的命令,则创建 Job,并运行;

        创建 Job 时,会根据具体客户端传递的命令,找到对应的 Command,并包装成 Process, Process 再被包装成 Job;

        运行 Job 时,反向先调用 Process,再找到对应的 Command,最终调用 Command 的 process 处理请求。

    服务端——Command 处理流程

        不需要使用字节码增强的命令

            其中 JVM 相关的使用 java.lang.management 提供的管理接口,来查看具体的运行时数据。

        需要使用字节码增强的命令

            字节码增加的命令统一继承 EnhancerCommand 类,process 方法里面调用 enhance 方法进行增强。调用 Enhancer 类 enhance 方法,该方法内部调用 inst.addTransformer 方法添加自定义的 ClassFileTransformer,这边是 Enhancer 类。

            Enhancer 类使用 AdviceWeaver(继承 ClassVisitor),用来修改类的字节码。重写了 visitMethod 方法,在该方法里面修改类指定的方法。visitMethod 方法里面使用了 AdviceAdapter(继承了 MethodVisitor类),在 onMethodEnter 方法, onMethodExit 方法中,把 Spy 类对应的方法(ON_BEFORE_METHOD, ON_RETURN_METHOD, ON_THROWS_METHOD 等)编织到目标类的方法对应的位置。

            在前面 Spy 初始化的时候可以看到,这几个方法其实指向的是 AdviceWeaver 类的 methodOnBegin, methodOnReturnEnd 等。在这些方法里面都会根据 adviceId 查找对应的 AdviceListener,并调用 AdviceListener 的对应的方法,比如 before,afterReturning, afterThrowing。

客户端

    客户端代码在 arthas-client 模块里面,入口类是 com.taobao.arthas.client.TelnetConsole。

    主要使用 apache commons-net jar 进行 telnet 连接,关键的代码有下面几步:

        构造 TelnetClient 对象,并初始化

        构造 ConsoleReader 对象,并初始化

        调用 IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in, consoleReader.getOutput()) 处理各个流,一共有四个流:

        telnet.getInputStream()

        telnet.getOutputStream()

        System.in

        consoleReader.getOutput()

    请求时:从本地 System.in 读取,发送到 telnet.getOutputStream(),即发送给远程服务端。 响应时:从 telnet.getInputStream() 读取远程服务端发送过来的响应,并传递给 consoleReader.getOutput(),即在本地控制台输出。



参考文献

开源地址:

https://github.com/alibaba/arthas

官方文档:

https://arthas.aliyun.com/doc/

文章借鉴:

https://www.cnblogs.com/alisystemsoftware/p/13107988.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容