线上问题定位分析宝典-Arthas篇

1 Arthas介绍

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

Arthas 用户文档:https://arthas.aliyun.com/doc/

对于如何使用Arthas官方文档做得非常详细,本篇主要内容概要:

  1. 对Arthas命令按作用对象进行了分类
  2. 对于典型故障场景,分享如何使用Arthas查找问题原因并使用Arthas救火。
  3. 分享如何使用arthas获取Spring context容器并获取项目中的bean。
  4. 最后分享实例即将OOM时,如何使用Arthas清理无用的全局对象,以避免OOM。

2 常用命令归类

arthas有40多个工具命令,下面列出的是处理问题常用的工具

看板

dashboard

线程栈

thread

方法相关

watch、trace、stack、tt、monitor、sm

类相关

getstatic、sc、jad、classloader、dump

日志调整

logger

jvm相关

jvm、sysenv、sysprop、jvmoption、perfcounter、heapdump、mbean

手动运行静态方法

ognl

热更新代码

mc、redefine/retransform

2.1 线程(thread)

参数名称

参数说明和用途

示例

id

查看指定线程的堆栈

thread 1

[-n:]

指定最忙的前N个线程并打印堆栈

thread -n 5

[-b]

找出当前阻塞其他线程的线程

thread -b

[-i <value>]

指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200

thread -i 2000

[--all]

显示所有匹配的线程

thread --all

thread命令局限性:

  1. 不能一次打印全部线程的stack,对于waitting状态的异常线程需要逐一查看堆栈。解决办法是使用jdk的jstack命令。

2.2 方法相关

命令

公共参数

可选常用参数

主要用途和场景

watch

class-pattern: 类名

method-pattern: 方法名

<condition-express>: 条件表达式(ognl)

[-n, --limits <value>]: 执行次数,默认100

[-E, --regex]: 使用正则表达式

[--exclude-class-pattern <value>]: 排除类

[--listenerId <value>]:追加另一个监控ID

[-v, --verbose]: 打印verbose信息,默认false

[-b, --before]: 在方法调用之前观察

[-e, --exception]: 在方法异常之后观察

[-s, --success]: 在方法返回之后观察

[-f , --finish]: 在方法结束之后(正常返回和异常返回)观察,默认开启

<express>: 观察表达式,即要观察的内容(ognl)

[-x, --expand <value>] 观察结果展开级别,默认1

[-M, --sizeLimite <value>] 结果大小,默认10M

用于方法执行数据观测,入参、返回值、异常、当前调用对象等

  1. 查看异常情况下的参数、返回值

  2. 查看高耗时情况下的参数

  3. 查看特定条件下的参数、返回值、异常信息

  4. 打印异常堆栈

trace

[--skipJDKMethod <value>]跳过sdk方法,默认true

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

  1. 追踪方法中哪一步耗时非常高

  2. 追踪方法中哪一步抛出异常

stack

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

  1. 查看异常情况下的调用栈

  2. 查看方法在哪些地方有调用

monitor

[-b, --before]: 在方法调用之前执行条件表达式

[-c, --cycle <value>] 监控周期,默认60秒

方法执行监控,耗时、调用次数、异常次数统计

  1. 监控方法性能

tt

保存记录:

[-t, --time-tunnel]开启tt记录

[-M, --sizeLimite <value>] 结果大小,默认10M

查看记录:

[-l, --list]列出当前所有记录

[-s, --search-express <value>] 搜索表达式(ognl)

[-i, --index <value>]使用指定索引号的记录

[-w, --watch-express <value>] 查看表达式(ognl)

[-x, --expand <value>] 观察结果展开级别,默认1

[-p, --play] 重新执行指定索引号的记录

[--replay-interval <value>] 执行时长

[--replay-times <value>] 执行次数

删除记录:

[-d <value>] [--delete-all] 删除tt记录

作用:保存方法每次调用的入参和返回信息,并能观测分析对这些信息。结合其它命令还可做线上debug

  1. 创建快照

tt -t com.xxx.Class1 method1 -n 1

  1. 查看已有快照

tt -l

  1. 查看id为1000的快照中方法参数

tt -i 1000 -w 'params'

  1. 重新执行方法,以id为1000的快照数据为例

tt -i 1000 -p

  1. 删除快照

tt --delete-all

ognl表达式内置对象和变量:target、params、returnObj、throwExp、isThrow、#cost

2.3 类相关常用命令

命令

公共参数

可选常用参数

主要用途

sc

class-pattern: 类名

[-c <value>]: 指定类加载器的hash值

[--classLoaderClass <value>]: classloader类名

[-n, --limits <value>]: 执行次数,默认100

[-E, --regex]: 使用正则表达式

[-d, --detail]: 详细信息

[-f, --field]: 显示类所有的成员变量

[-x, --expand <value>] 观察结果展开级别,默认0

查看JVM已加载的类信息

  1. 查看类的加载器hash值

  2. 查看类所在jar包版本,检查jar包冲突

  3. 继承结构

getstatic

<field-pattern> 静态变量名

<express> 观察表达式,即要观察的内容(ognl)

[-x, --expand <value>] 观察结果展开级别,默认1

  1. 查看静态变量值

jad

[--source-only] 只展示反编译代码

<method-name>只反编译指定方法

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

  1. 查看类源码

  2. 查看指定方法的源码

2.4 其它常用命令

命令

公共参数

可选常用参数

主要用途

logger

[-c <value>]: 指定类加载器的hash值

[--classLoaderClass <value>]: classloader类名

[-n, --name] logger名称,根logger为root

[-l, --level] 设置日志级别

  1. 调整日志级别

  2. 查看日志级别

ognl

<express> 观察表达式,即要观察的内容(ognl)

[-x, --expand <value>] 观察结果展开级别,默认1

执行OGNL表达式

  1. 查看对象数据

  2. 运行指定方法

3 典型业务故障分析

  1. cpu负载高问题如何定位原因?

  2. 接口耗时飙升如何定位原因?

  3. 接口异常如何定位数据不正确的原因?

3.1 CPU负载高问题定位

3.1.1 问题定位思路

在流量不大的情况下,cpu负载高可能是因为循环次数非常大甚至死循环

  1. 找到耗CPU高的进程

  2. 找到进程内耗CPU高的线程

  3. 找到线程内耗CPU高的代码行

通常做法

#找到占CPU大的进程
top 
#找到占CPU高的线程
top -p 进程号 -H 
#将线程ID转换为16进制
printf "%x\n" tid 
jstack pid | grep 16进制tid #打印线程堆栈

3.1.2 Arthas如何定位?

#查看占用CPU比较大的前10个线程
thread -n 10 
#查看指定id号的线程堆栈,找到问题代码行
thread id 
#查看源码,如果没有源码,反编译指定方法
jad com.xx.yy.zz.Class1 method 1

3.1.3 跳出死循环

问题:在不能立马上线的情况下,如何立马解决死循环?

  1. 如果循环内有sleep/wait/await等阻塞方法,可通过循环内watch某个方法,在ognl表达式中获取线程实例并执行interrupt方法

watch com.xx.arthas.Demo1 run '@java.lang.Thread@currentThread().interrupt()' -n 1
  1. 使用ognl表达式修改对象属性值以满足循环终止条件

  2. 使用ognl表达式修改对象属性值以便往循环外抛出异常

  3. 没法终止线程,可通过循环内watch某个方法,在ognl表达式中使线程休眠让出CPU

watch com.xx.arthas.Demo1 run '@java.lang.Thread@sleep(20000)' -b &

3.2 接口耗时飙升问题定位

3.2.1 根因典型场景

  1. CPU负载高(定位方法上面提过)

  2. 网络流量大、延迟

  3. 磁盘负载

  4. 远程方法调用耗时

  5. 数据库访问耗时

  6. 粗粒度的线程同步块

  7. 程序执行步骤多,时间复杂度高

  8. 数据量大处理速度慢

  9. 与高耗时的任务共用线程池资源

  10. 连接池小或者连接对象放回连接池时间延迟

3.2.2 问题定位思路

  1. 排除硬件环境因素,如CPU、磁盘、网络、内存。(top\free\dstat命令)

  2. 排除数据库(mysql/redis/ES等)性能问题(数据库监控)

  3. 排除第三方接口耗时

  4. 排查内部接口耗时

  5. 检查代码逻辑

痛点,上面排查过程,耗时也非常长,如果每步平均要2分钟,定位一个问题也要10分钟左右,如果有一个很快排除其它因素而定位到问题原因或者方向的工具就太好了,而使用arthas可以勉强做到。

3.2.3 Arthas使用

  1. 启动arthas

  2. 执行dashboard命令查看有无占CPU高的线程、内存、gc情况

  3. 从问题方法开始,逐层从耗时高的方法节点使用trace命令,最终找到耗时高的外部接口或内部方法

#查看jvm实时状况
dashboard 

#追踪耗时100ms以上的请求,在方法中哪一步执行比较耗时
trace com.xx.Class1 method1 '#cost>100' 

#重复第一步逐层追踪,也可以用下面正则表达式同时追踪多个方法
trace -E com.xx.Class1|com.yy.Class2|...|Classn   method1|method2|...|methodn '#cost>100'

辅助命令:

stack: 查看问题方法的调用栈,用于回溯问题方法被调用的源头,定位方法参数的传输路径

watch: 查看问题方法执行的参数、返回值,用于定位数据量大造成方法处理时间长、网络传输慢

jad: 反编译源代码查看代码逻辑

技巧:

trace的过程借助源代码分析进行,避免不必要的trace操作,以免耽误更多时间

3.1.4 内部接口耗时飙升

典型原因
  1. 数据量大,造成循环次数过多

  2. 粗粒度的线程同步块,锁竞争

  3. wait/sleep等阻塞方法时间长

问题分析思路
  1. 查看方法入参和调用者对象信息

  2. 查看代码源码

Arthas使用

以上原因都可以用下面命令排查

#查看jvm实时状况
dashboard 
#追踪耗时100ms以上的请求,在方法中哪一步执行比较耗时
trace com.xx.Class1 method1 '#cost>100' 
#重复第一步逐层追踪,也可以用下面正则表达式同时追踪多个方法
trace -E com.xx.Class1|com.yy.Class2|...|Classn   method1|method2|...|methodn '#cost>100'

3.1.6 Mysql查询超时

典型原因
  1. SQL中没有使用索引

  2. 请求数据量大

  3. 连接池连接获取延迟

分析思路
  1. 查看SQL

  2. 查看mysql返回数据量大小

  3. 连接获取耗时高时查看连接池信息

  4. 连接获取耗时高时查看追踪方法耗时点

Arthas使用
#查看SQL
watch java.sql.Statement execute* '{params, target}' -x 3 '#cost>50'

#追踪耗时超过20ms时,获取连接的执行步骤中哪一步耗时高
trace javax.sql.DataSource getConnection '#cost>20' 

3.3 流程逻辑异常分析

3.3.1 不能定位到抛出异常的代码点在哪里

原因:没有异常栈信息,不能定位问题

Arthas使用
trace com.xx.Class1 method1
  1. 通过trace命令就可以看到方法内部执行了哪些行的代码

  2. 结合源代码查看哪一步没有执行,那么异常就在上一步中抛出

  3. 找到异常点,分析异常原因

3.3.2 异常原因定位

异常发生,堆栈也有。如果找不到异常点,看上一节。由于参数不正确造成异常,那么如何找到造成参数不正确的原因呢?

典型原因
  1. 源头传入的参数就不正确

  2. 方法在执行流程中更改了数据

  3. 全局状态在某个异常时被更改,而异常点不明且不能复现。正常流程获取不到正确的状态而抛异常。

  4. jar包冲突

  5. jar包版本问题

Arthas使用
#查看源头方法参数
watch com.xx.Class1 method1 params -x 3 
#查看哪个地方修改了方法
stack com.xx.Class2 setMethod2 
sc -d com.xx.Class1

4 其他场景技巧

4.1 获取SpingContext

获取方法

  1. 从dubbo中获取

ognl '#c = @org.apache.dubbo.config.spring.extension.SpringExtensionFactory@CONTEXTS.iterator().next(),#c.getBean("beanName")' -c 6bb489f8 
  1. Spring mvc使用tt命令获取(需要触发一条http请求)

tt -t org.springframework.web.servlet.DispatcherServlet doService -n 1
tt -i 1000 -w '#c=target.webApplicationContext, #c.getBean("beanName")'

适用场景

  1. 查看某个bean是否被正确初始化,比如查看参数是否正确

  2. 想要手动触发某个bean的方法来处理线上问题

  3. 想要复现线上问题

4.2 查看异常调用栈

无异常堆栈时,如何查看调用堆栈?

watch demo.MathGame primeFactors "{params, throwExp, @java.lang.Thread@currentThread().getStackTrace()}"  -x 2 -e

4.3 调整日志级别

logger -n com.xx -l info -c 6bb489f8

注意,

  1. 建议指定-c参数,即类加载器的hash值

  2. 生产上修改日志级别后,别忘了调整回来

4.4 OOM

典型原因

  1. jvm内存设置太小

  2. 创建对象的速度大于垃圾回收的速度

  3. 代码问题,有大量本应该释放引用的对象没被释放,这样的对象随着时间的增长而增长,而GC不掉,最终OOM。

处理方式

针对第3个问题,dump出jvm内存数据进行分析,找到那些无用的对象的持有者,比如是一个静态Map实例,可使用ognl表达式清除map中的数据,以便可以GC掉,如

ognl '@com.xx.Class1@staticMap.clear()'

也可以用watch命令在后台按照一定条件清理,如

watch com.xx.Class1 method '@com.xx.Class1@staticMap.size()>1000&& @com.xx.Class1@staticMap.clear()' &

5. 总结

  1. mc、redefine:mc组合rdefine可以对代码进行热更新,不满足生产运行管理规范要求。
  2. JVM内存不足,arthas挂上去可能导致系统崩溃;
  3. 用完Arthas一定要执行stop清除arthas在应用中加载的类和对象,session掉了也要重新连接后stop;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/760634.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++ 设计模式 的课本范例(下)

&#xff08;19&#xff09; 桥接模式 Bridge&#xff0c;不是采用类继承&#xff0c;而是采用类组合&#xff0c;一个类的数据成员是类对象&#xff0c;来扩展类的功能。源码如下&#xff1a; class OS // 操作系统负责绘图 { public:virtual ~OS() {}virtual void draw(cha…

昇思25天学习打卡营第13天|MindNLP ChatGLM-6B StreamChat

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) MindNLP ChatGLM-6B StreamChat 本案例基于MindNLP和ChatGLM-6B实现一个聊天应用。 1 环境配置 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspo…

使用 Swift 递归搜索目录中文件的内容,同时支持 Glob 模式和正则表达式

文章目录 前言项目设置查找文件读取CODEOWNERS文件解析规则搜索匹配的文件确定文件所有者输出结果总结前言 如果你新加入一个团队,想要快速的了解团队的领域和团队中拥有的代码库的详细信息。 如果新团队中的代码库在 GitHub / GitLab 中并且你不熟悉代码所有权模型的概念或…

Burpsuite靶场信息泄露相关的实验通关

目录 第一关&#xff1a;错误消息中的信息披露 第二关&#xff1a;调试页面信息披露 第三关&#xff1a;通过备份文件披露源代码 第四关&#xff1a;通过信息披露绕过身份验证 第五关&#xff1a;版本控制历史中的信息披露 最近看大佬的文章&#xff0c;发现了很对自己没有…

鲁工小装载机-前后桥传动轴油封更换记录

鲁工装载机 因前后桥大量漏齿轮油&#xff0c;故拆开查看、更换油封 一&#xff1a; 如图圈起来的地方是螺丝和钢板相别&#xff0c;用200的焊接电流用电焊机点开一个豁口后拆除螺丝。 转轴是拆除传动轴后的样子。 这就是拆下来的样子&#xff0c;这玩意插上边那图&…

2024最新初级会计职称题库来啦!!!

16.根据增值税法律制度的规定&#xff0c;下列各项中&#xff0c;属于"提供加工、修理修配劳务"的是&#xff08;&#xff09;。 A.修理小汽车 B.修缮办公楼 C.爆破 D.矿山穿孔 答案&#xff1a;A 解析&#xff1a;选项AB&#xff1a;修理有形动产&#xff08;…

江协科技51单片机学习- p21 LED点阵屏(8*8)

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

发那科机床采集数据

前面两篇重点介绍了理论&#xff0c;从这篇开始&#xff0c;我们开始进行实战。首先从发那科机床开始&#xff0c;为何第一个将发那科。因为发那科系统机床有三最。最广泛&#xff08;中国保有量最多&#xff09;、 最多资料&#xff08;发那科系统的开发包历史悠久&#xff0c…

【效率提升】新一代效率工具平台utools

下载地址&#xff1a;utools uTools这款软件&#xff0c;是一款功能强大且高度可定制的效率神器&#xff0c;使用快捷键alt space(空格) 随时调用&#xff0c;支持调用系统应用、用户安装应用和市场插件等。 utools可以调用系统设置和内置应用&#xff0c;这样可以方便快捷的…

Python计算n的阶乘的多种方法

1 问题 在课上&#xff0c;我们学习了用递归函数去计算一个自然数n的阶乘。但计算一个自然数n的阶乘是否就这一种方法呢&#xff1f; 2 方法 关于计算一个自然数n的阶乘&#xff0c;通过搜索&#xff0c;我们寻找到了除运用递归函数外的其他三种方法&#xff1a; 方法一 通过导…

CSS-实例-div 水平居中 垂直靠上

1 需求 2 语法 3 示例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格水平居中、垂直靠上示例…

解决Install/Remove of the Service Denied报错

1、问题概述&#xff1f; 在Windows系统中安装MySQL5.7.43的时候&#xff0c;运行mysqld install命令提示报错&#xff1a;Install/Remove of the Service Denied 意思是&#xff1a;安装/删除服务被拒绝 问题原因所在&#xff1a;就是你当前的权限不够&#xff0c;以管理员…

人工智能的目标分类

欢迎来到 Papicatch的博客 目录 &#x1f349;引言 &#x1f349;目标分类的概述 &#x1f348;背景 &#x1f348;分类的重要性 &#x1f34d;明确研究重点 &#x1f34d;促进应用推广 &#x1f34d;便于评估和比较 &#x1f348;分类的原则 &#x1f34d;基于应用领…

密钥库jks文件加载格式错误IOException:Invalid keystore format--已经解决

一、报错 java.lang.RuntimeException: java.io.IOException: Invalid keystore format Caused by: java.io.IOException: Invalid keystore format二、原因 原因&#xff1a;Java的密钥库jks文件放在/src/main/resources目录下,编译后jks文件被修改,导致keyStore.load读取…

支付宝支付之收款码支付

文章目录 收款码支付接入流程安全设计系统交互流程交易状态统一收单交易支付接口请求参数测试结果查询支付撤销支付退款支付退款结果退款说明 收款码支付 继&#xff1a;支付宝支付之入门支付 接入流程 安全设计 支付宝为了保证交易安全采取了一系列安全手段以保证交易安全。…

计网之IP

IP IP基本认识 不使用NAT时&#xff0c;源IP地址和目的IP地址不变&#xff0c;只要源MAC和目的MAC地址在变化 IP地址 D类是组播地址&#xff0c;E类是保留地址 无分类地址CIDR 解决直接分类的B类65536太多&#xff0c;C类256太少a.b.c.d/x的前x位属于网路号&#xff0c;剩…

kafka的工作原理与常见问题

定义 kafka是一个分布式的基于发布/订阅模式的消息队列&#xff08;message queue&#xff09;&#xff0c;主要应用于大数据的实时处理领域 消息队列工作原理 kafka的组成结构 kafka的基础架构主要有broker、生产者、消费者组构成&#xff0c;还包括zookeeper. 生产者负责发送…

高并发场景下的热点key问题探析与应对策略

目录 一、问题描述 二、发现机制 三、解决策略分析 &#xff08;一&#xff09;解决策略一&#xff1a;多级缓存策略 客户端本地缓存 代理节点本地缓存 &#xff08;二&#xff09;解决策略二&#xff1a;多副本策略 &#xff08;三&#xff09;解决策略三&#xff1a;热点…

计算机组成原理——锁存器和触发器

文章目录 1. SR锁存器 1.1 电路结构 1.2 电路解析 2. 带en输入的SR锁存器 2.1 ​​​​​​​电路结构 2.2 工作原理 3. ​​​​​​​带En输入的D锁存器 3.1 电路结构 3.2 工作原理 4. ​​​​​​​边沿触发的D触发器 4.1 电路结构 4.2 工作原理 1. SR锁存器 …

Python | Leetcode Python题解之第207题课程表

题目&#xff1a; 题解&#xff1a; class Solution:def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:edges collections.defaultdict(list)indeg [0] * numCoursesfor info in prerequisites:edges[info[1]].append(info[0])indeg[info[…