一篇学会Arthas的基本使用及常用指令
2024/12/23 11:17:52
来源:https://blog.csdn.net/qq_51081923/article/details/135703449
浏览:
次
关键词:一篇学会Arthas的基本使用及常用指令
将jar包下载后放到指定的文件夹中 win+r打开命令行使用命令运行arthas对应的jar包 java -jar D:\application\arthas\arthas-boot.jar会列出所有的java服务选择要监控的服务,输入服务列表索引数字后回车,就能正常启动了如果回车后报端口已经被使用,说明之前arthas服务绑定监控的服务后没有正常结束就退出了,绑定关系依然存在。启动之后如果需要结束arthas服务则使用命令quit或者stop 启动之后可以直接访问Arthas Console 使用和终端类似 dashboard
全局监控可以概览程序的 线程、内存、GC、运行环境信息。 线程监控使用 thread查看所有线程信息,同时会列出每个线程的 CPU 使用率。可以用来检查哪些线程占用CPU较高使用“thread 【线程id】”来查看该线程的信息使用“thread -n [显示的线程个数]”来查看thread -n [显示的线程个数] - 可以根据列出的线程信息判断具体哪个方法占用的cpu较高
使用“thread | grep pool”查看线程池里线程信息。 运行中、阻塞、等待等使用“thread -b”如果服务中存在死锁,则可以直接定位到死锁的位置 jad
可以使用jad将对应的代码进行发编译查看环境中的代码jad 【全限定类名】 使用 **sc -d -f ** 命令查看类的字段信息。 使用 sm 命令查看类的方法信息。 在Arthas中可以通过ognl表达式在java程序的运行阶段获取java类的静态方法、调用静态方法、new出对象操作成员属性和方法等操作。这些能力可以用于排查线上一些奇奇怪怪的问题,比如感觉线上某个静态属性值不对,可以通过ognl表达式获取对应的静态属性值查看,又或者在Spring项目中注入对象都是单例的,可以通过getBean(name)的方式获取到具体的单例对象,然后对这个单例对象进行操作,同时也能调用对象中的一些方法,在不提供http接口的情况下实现某些特定的线上测试。例子获取静态属性ognl表达式 ognl '@com.example.OgnlDemo01@s1'调用静态方法 无参:ognl '@com.example.OgnlDemo01@printS12()'有参:ognl '@com.example.OgnlDemo01@setS12("my-s1","my-s2")'使用ognl表达式操作对象的非静态属性和非静态方法 - 要操作非静态属性或方法前一定是对象已经被new出来了,我们通过一个入口找到这个被创建的对象从而操作对象的属性和方法,就比如Spring中可以通过上下文对象获取到一个指定的对象,从而进行操作,又或者通过ognl表达式直接创建一个对象,然后对这个对象进行操作,又或者使用静态属性对象操作。
- 测试代码:
public class OgnlDemo02 {public static String s1="s1-public-static-v";public String s2="s2-public-v";private String s3="s3-private-v";public static OgnlDemo02 ognlDemo02=new OgnlDemo02();public String getS1() {return OgnlDemo02.s1;}public void setS1(String s1) {OgnlDemo02.s1 = s1;}public String getS2() {return s2;}public void setS2(String s2) {this.s2 = s2;}public String getS3() {return s3;}public void setS3(String s3) {this.s3 = s3;}}
-
- 调用非静态方法ognl表达式
- 通过静态属性ognlDemo02对象调用非静态方法
- ognl '@com.kerwin.arthas.demo.OgnlDemo02@ognlDemo02.getS1()'
- 使用ognl表达式创建一个对象,并对这个对象进行操作
-
public class User {private Long uid;private String nickName;public User(Long uid, String nickName) {this.uid = uid;this.nickName = nickName;}public Long getUid() {return uid;}public void setUid(Long uid) {this.uid = uid;}public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}}
-
-
# 创建一个User对象什么也不做[arthas@27880]$ ognl 'new com.kerwin.arthas.demo.User(100,"kerwin")' @User[ uid=@Long[100], nickName=@String[kerwin], ]# 创建一个User对象赋值给user,后续可以在别的地方对创建出来的对象进行操作[arthas@27880]$ ognl '#user = new com.kerwin.arthas.demo.User(100,"kerwin")' @User[ uid=@Long[100], nickName=@String[kerwin], ]
-
-
-
[arthas@27880]$ ognl 'new com.kerwin.arthas.demo.User(10001,"kerwin").getNickName()' @String[kerwin] ][arthas@27880]$ ognl '#user = new com.kerwin.arthas.demo.User(10001,"kerwin").getNickName()' @String[kerwin] ][arthas@27880]$ ognl '#user = new com.kerwin.arthas.demo.User(10001,"kerwin"),#user.getNickName()' @String[kerwin] ]
-
-
public class OgnlDemo03 {public static OgnlDemo03 ognlDemo03 = new OgnlDemo03();private User user;private static User staticUser;private static List<String> lists;private static Map<String,String> maps;public User setUser(User user){this.user = user;return user;}public static User setStaticUser(User user){OgnlDemo03.staticUser = user;return user;}public static User getMyUser(){return new User(10002L,"kerwin2");}public static User changeUser(User user){return new User(user.getUid(),user.getNickName()+"---changeUser");}public static List<String> setLists(List<String> lists){OgnlDemo03.lists = lists;return lists;}public static Map<String,String> setMaps(Map<String,String> maps){OgnlDemo03.maps = maps;return maps;}}
-
-
- 自定义对象入参
- 创建一个User对象将这个对象作为参数传入静态方法中
-
[arthas@24600]$ ognl '#user = new com.kerwin.arthas.demo.User(10001,"kerwin"),@com.kerwin.arthas.demo.OgnlDemo03@setStaticUser(#user)' @User[ uid=@Long[10001], nickName=@String[kerwin], ]
-
-
-
- 创建一个User对象,将这个对象作为参数传入静态属性ognlDemo03对象setUser(user)方法中
-
[arthas@24600]$ ognl '#user = new com.kerwin.arthas.demo.User(10001,"kerwin"),@com.kerwin.arthas.demo.OgnlDemo03@ognlDemo03.setUser(#user)' @User[ uid=@Long[10001], nickName=@String[kerwin], ]
-
-
-
- 创建一个User对象,在创建一个OgnlDemo03对象,将创建的User对象传入OgnlDemo03对象的setUser(user)方法
-
[arthas@24600]$ ognl '#user = new com.kerwin.arthas.demo.User(10001,"kerwin"),new com.kerwin.arthas.demo.OgnlDemo03().setUser(#user)' @User[ uid=@Long[10001], nickName=@String[kerwin], ]
-
-
-
- 调用getMyUser()方法获取User对象作为changeUser(user)的入参
-
# {#user1,#user2} 代表将user1、user2这两个对象作为数组输出在控制台,因为这里没有加-x 2默认展开层级为1所以输出的是对象内存地址[arthas@18904]$ ognl '#user1 = @com.kerwin.arthas.demo.OgnlDemo03@getMyUser(),#user2 = @com.kerwin.arthas.demo.OgnlDemo03@changeUser(#user1),{#user1,#user2}' @ArrayList[ @User[com.kerwin.arthas.demo.User@30833e75], @User[com.kerwin.arthas.demo.User@70ca5419], ]# 加上-x 2 可以展开数组内部对象 [arthas@18904]$ ognl '#user1 = @com.kerwin.arthas.demo.OgnlDemo03@getMyUser(),#user2 = @com.kerwin.arthas.demo.OgnlDemo03@changeUser(#user1),{#user1,#user2}' -x 2 @ArrayList[ @User[ uid=@Long[10002], nickName=@String[kerwin2], ], @User[ uid=@Long[10002], nickName=@String[kerwin2---changeUser], ], ]
-
-
-
[arthas@18904]$ ognl '@com.kerwin.arthas.demo.OgnlDemo03@setLists({"k1","k2","k3"})' @ArrayList[ @String[k1], @String[k2], @String[k3], ]
-
-
-
[arthas@18904]$ ognl '#map = #{"id":10003L,"nickName":"k3"},@com.kerwin.arthas.demo.OgnlDemo03@setMaps(#map)' @LinkedHashMap[ @String[id]:@Long[10003], @String[nickName]:@String[k3], ]
- 实践操作:使用ognl表达式获取Spring上下文中对象,并进行操作
-
@Servicepublic class OgnlDemoService {private String description;public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}}
-
-
- 获取Spring上下文中的OgnlDemoService对象
-
# 通过beanName获取[arthas@30000]$ ognl '@com.example.test_mybatis.controller.SpringApplicationContext@getBean("ognlDemoService")' @OgnlDemoService[ description=null, ]# 通过class获取 [arthas@30000]$ ognl '#OgnlDemoServiceClass =@com.example.test_mybatis.service.OgnlDemoService@class,@com.kerwin.arthas.utils.SpringApplicationContext@getBean(#OgnlDemoServiceClass)' @OgnlDemoService[ description=null, ]
-
- 操作OgnlDemoService对象中变量和方法
-
[arthas@30000]$ ognl '@com.example.test_mybatis.controller.SpringApplicationContext@getBean("ognlDemoService").description' null [arthas@30000]$ ognl '@com.example.test_mybatis.controller.SpringApplicationContext@getBean("ognlDemoService").setDescription("HelloW orld")' null [arthas@30000]$ ognl '@com.example.test_mybatis.controller.SpringApplicationContext@getBean("ognlDemoService").getDescription()' @String[Hello World]
-
trace
- 使用 trace 命令可以跟踪统计方法耗时,经常用于排查运行较慢、耗时较长的场景
- 测试代码
-
package com.example.test_mybatis.controller;import com.example.test_mybatis.service.UserServiceImpl;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;@RestController@Slf4jpublic class UserController {@Autowiredprivate UserServiceImpl userService;@GetMapping(value = "/user")public HashMap<String, Object> getUser(Integer uid) throws Exception {// 模拟用户查询userService.get(uid);HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("uid", uid);hashMap.put("name", "name" + uid);return hashMap;}}package com.example.test_mybatis.service;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;@Service@Slf4jpublic class UserServiceImpl {public void get(Integer uid) throws Exception {check(uid);service(uid);redis(uid);mysql(uid);}public void service(Integer uid) throws Exception {int count = 0;for (int i = 0; i < 10; i++) {count += i;}log.info("service end {}", count);}public void redis(Integer uid) throws Exception {int count = 0;for (int i = 0; i < 10000; i++) {count += i;}log.info("redis end {}", count);}public void mysql(Integer uid) throws Exception {long count = 0;for (int i = 0; i < 10000000; i++) {count += i;}log.info("mysql end {}", count);}public boolean check(Integer uid) throws Exception {if (uid == null || uid < 0) {log.error("uid不正确,uid:{}", uid);throw new Exception("uid不正确");}return true;}}
- 在arthas中使用命令 trace com.example.test_mybatis.controller.UserController getUser
- 很清楚的看到是 com.UserServiceImpl的 mysql方法耗时是最高的。
-
- 使用 monitor 命令监控统计方法的执行情况。
-
watch
- 观察方法信息
- 常用方法
-
# 查看入参和出参$ watch com.Arthas addHashSet '{params[0],returnObj}'# 查看入参和出参大小$ watch com.Arthas addHashSet '{params[0],returnObj.size}'# 查看入参和出参中是否包含 'count10'$ watch com.Arthas addHashSet '{params[0],returnObj.contains("count10")}'# 查看入参和出参,出参 toString$ watch com.Arthas addHashSet '{params[0],returnObj.toString()}'
- 可以对传入的参数进行操作
-
stack
- 使用stack查看方法的调用情况 stack com.UserServiceImpl mysql
tt
tt 命令方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测 。使用 tt 命令记录方法执行的详细情况 开始记录方法调用信息:tt -t com.UserServiceImpl check查看记录的方法调用信息: tt -l查看调用记录的详细信息(-i 指定 INDEX): tt -i 1001重新发起调用,使用指定记录,使用 -p 重新调用。
版权声明:
本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。
我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com