线上调试BUG,就用阿里的这款诊断神器
yuyutoo 2025-07-06 17:44 4 浏览 0 评论
摘要
线上项目遇到问题无法调试,线下又无法重现,难道只能加日志再重新发布么?有了这款神器,既可以线上调试,又可以实现热修复,推荐给大家!
Arthas 简介
Arthas是Alibaba开源的Java诊断工具,深受开发者喜爱。它采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
安装
为了还原一个真实的线上环境,我们将通过Arthas来对Docker容器中的Java程序进行诊断。
- 使用arthas-boot,下载对应jar包,下载地址:alibaba.github.io/arthas/arth…
- 将我们的Spring Boot应用mall-tiny-arthas使用Docker容器的方式启动起来,打包和运行脚本在项目的src\main\docker目录下;
- 将arthas-boot.jar拷贝到我们应用容器的\目录下;
docker container cp arthas-boot.jar mall-tiny-arthas:/
复制代码
- 进入容器并启动arthas-boot,直接当做jar包启动即可;
docker exec -it mall-tiny-arthas /bin/bash
java -jar arthas-boot.jar
复制代码
- 启动成功后,选择当前需要诊断的Java程序的序列号,这里是1,就可以开始诊断了;
- 期间会下载一些所需的文件,完成后控制台打印信息如下,至此Arthas就安装启动完成了。
常用命令
我们先来介绍一些Arthas的常用命令,会结合实际应用来讲解,带大家了解下Arthas的使用。
dashboard
使用dashboard命令可以显示当前系统的实时数据面板,包括线程信息、JVM内存信息及JVM运行时参数。
thread
查看当前线程信息,查看线程的堆栈,可以找出当前最占CPU的线程。
常用命令:
# 打印当前最忙的3个线程的堆栈信息
thread -n 3
# 查看ID为1都线程的堆栈信息
thread 1
# 找出当前阻塞其他线程的线程
thread -b
# 查看指定状态的线程
thread -state WAITING
复制代码
sysprop
查看当前JVM的系统属性,比如当容器时区与宿主机不一致时,可以使用如下命令查看时区信息。
sysprop |grep timezone
复制代码
user.timezone Asia/Shanghai
复制代码
sysenv
查看JVM的环境属性,比如查看下我们当前启用的是什么环境的Spring Boot配置。
logger
使用logger命令可以查看日志信息,并改变日志级别,这个命令非常有用。
比如我们在生产环境上一般是不会打印DEBUG级别的日志的,当我们在线上排查问题时可以临时开启DEBUG级别的日志,帮助我们排查问题,下面介绍下如何操作。
- 我们的应用默认使用的是INFO级别的日志,使用logger命令可以查看;
- 使用如下命令改变日志级别为DEBUG,需要使用-c参数指定类加载器的HASH值;
logger -c 21b8d17c --name ROOT --level debug
复制代码
- 再使用logger命令查看,发现ROOT级别日志已经更改;
- 使用docker logs -f mall-tiny-arthas命令查看容器日志,发现已经打印了DEBUG级别的日志;
- 查看完日志以后记得要把日志级别再调回INFO级别。
logger -c 21b8d17c --name ROOT --level info
复制代码
sc
查看JVM已加载的类信息,Search-Class的简写,搜索出所有已经加载到 JVM 中的类信息。
- 搜索com.macro.mall包下所有的类;
sc com.macro.mall.*
复制代码
- 打印类的详细信息,加入-d参数并指定全限定类名;
sc -d com.macro.mall.tiny.common.api.CommonResult
复制代码
- 打印出类的Field信息,使用-f参数。
sc -d -f com.macro.mall.tiny.common.api.CommonResult
复制代码
sm
查看已加载类的方法信息,Search-Method的简写,搜索出所有已经加载的类的方法信息。
- 查看类中的所有方法;
sm com.macro.mall.tiny.common.api.CommonResult
复制代码
- 查看指定方法信息,使用-d参数并指定方法名称;
sm -d com.macro.mall.tiny.common.api.CommonResult getCode
复制代码
jad
反编译已加载类的源码,觉得线上代码和预期不一致,可以反编译看看。
- 查看启动类的相关信息,默认会带有ClassLoader信息;
jad com.macro.mall.tiny.MallTinyApplication
复制代码
- 使用--source-only参数可以只打印类信息。
jad --source-only com.macro.mall.tiny.MallTinyApplication
复制代码
mc
内存编译器,Memory Compiler的缩写,编译.java文件生成.class。
redefine
加载外部的.class文件,覆盖掉 JVM中已经加载的类。
monitor
实时监控方法执行信息,可以查看方法执行成功此时、失败次数、平均耗时等信息。
monitor -c 5 com.macro.mall.tiny.controller.PmsBrandController listBrand
复制代码
watch
方法执行数据观测,可以观察方法执行过程中的参数和返回值。
使用如下命令观察方法执行参数和返回值,-x表示结果属性遍历深度。
watch com.macro.mall.tiny.service.impl.PmsBrandServiceImpl listBrand "{params,returnObj}" -x 2
复制代码
热更新
尽管在线上环境热更代码并不是一个很好的行为,但有的时候我们真的很需要热更代码。下面介绍下如何使用jad/mc/redefine来热更新代码。
- 首先我们有一个商品详情的接口,当我们传入id<=0时,会抛出IllegalArgumentException;
/**
* 品牌管理Controller
* Created by macro on 2019/4/19.
*/
@Api(tags = "PmsBrandController", description = "商品品牌管理")
@Controller
@RequestMapping("/brand")
public class PmsBrandController {
@Autowired
private PmsBrandService brandService;
private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);
@ApiOperation("获取指定id的品牌详情")
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
if(id<=0){
throw new IllegalArgumentException("id not excepted id:"+id);
}
return CommonResult.success(brandService.getBrand(id));
}
}
复制代码
- 调用接口会返回如下信息,调用地址:http://192.168.5.94:8088/brand/0
{
"timestamp": "2020-06-12T06:20:20.951+0000",
"status": 500,
"error": "Internal Server Error",
"message": "id not excepted id:0",
"path": "/brand/0"
}
复制代码
- 我们想对该问题进行修复,如果传入id<=0时,直接返回空数据的CommonResult,代码修改内容如下;
/**
* 品牌管理Controller
* Created by macro on 2019/4/19.
*/
@Api(tags = "PmsBrandController", description = "商品品牌管理")
@Controller
@RequestMapping("/brand")
public class PmsBrandController {
@Autowired
private PmsBrandService brandService;
private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);
@ApiOperation("获取指定id的品牌详情")
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
if(id<=0){
// throw new IllegalArgumentException("id not excepted id:"+id);
return CommonResult.success(null);
}
return CommonResult.success(brandService.getBrand(id));
}
}
复制代码
- 首先我们需要对PmsBrandController类代码进行修改,接着上传到服务器,然后使用如下命令将java文件拷贝到容器的/tmp目录下;
docker container cp /tmp/PmsBrandController.java mall-tiny-arthas:/tmp/
复制代码
- 之后我们需要查看该类的类加载器的Hash值;
sc -d *PmsBrandController | grep classLoaderHash
复制代码
- 之后使用内存编译器把改.java文件编译成.class文件,注意需要使用-c指定类加载器;
mc -c 21b8d17c /tmp/PmsBrandController.java -d /tmp
复制代码
- 最后使用redefine命令加载.class文件,将原来加载的类覆盖掉;
redefine -c 21b8d17c /tmp/com/macro/mall/tiny/controller/PmsBrandController.class
复制代码
- 我们再次调用接口进行测试,发现已经返回了预期的结果,调用地址:http://192.168.3.101:8088/brand/0
{
"code": 200,
"message": "操作成功",
"data": null
}
复制代码
参考资料
官方文档:alibaba.github.io/arthas/
作者:MacroZheng
链接:
https://juejin.im/post/5f017dd56fb9a07e953df64b
相关推荐
- 全局和隐式 using 指令详解(全局命令)
-
1.什么是全局和隐式using?在.NET6及更高版本中,Microsoft引入了...
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
-
1、介绍模块化单体是一种架构风格,代码是根据模块的概念构成的。对于许多组织而言,模块化单体可能是一个很好的选择。它有助于保持一定程度的独立性,这有助于我们在需要的时候轻松过渡到微服务架构。Spri...
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
-
我是一位多年后端经验的工程师,其中前几年用ASP.NET...
- .NET AOT 详解(.net 6 aot)
-
简介AOT(Ahead-Of-TimeCompilation)是一种将代码直接编译为机器码的技术,与传统的...
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
-
哈喽,我是老鱼,一名致力于在技术道路上的终身学习者、实践者、分享者!...
- asar归档解包(游戏arc文件解包)
-
要学习Electron逆向,首先要有一个Electron开发的程序的发布的包,这里就以其官方的electron-quick-start作为例子来进行一下逆向的过程。...
- 在PyCharm 中免费集成Amazon CodeWhisperer
-
CodeWhisperer是Amazon发布的一款免费的AI编程辅助小工具,可在你的集成开发环境(IDE)中生成实时单行或全函数代码建议,帮助你快速构建软件。简单来说,AmazonCodeWhi...
- 2014年最优秀JavaScript编辑器大盘点
-
1.WebstormWebStorm是一种轻量级的、功能强大的IDE,为Node.js复杂的客户端开发和服务器端开发提供完美的解决方案。WebStorm的智能代码编辑器支持JavaScript,...
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
-
项目简介:基于JS的超轻量级聊天软件。前端:vue、iview、electron实现的PC桌面版聊天程序,主要适用于私有云项目内部聊天,企业内部管理通讯等功能,主要通讯协议websocket。支持...
- JetBrains Toolbox推出全新产品订阅授权模式
-
捷克知名软件开发公司JetBrains最为人所熟知的产品是Java编程语言开发撰写时所用的集成开发环境IntelliJIDEA,相信很多开发者都有所了解。而近期自2015年11月2日起,JetBr...
- idea最新激活jetbrains-agent.jar包,亲测有效
-
这里分享一个2019.3.3版本的jetbrains-agent.jar,亲测有效,在网上找了很多都不能使用,终于找到一个可以使用的了,这里分享一下具体激活步骤,此方法适用于Jebrains家所有产品...
- CountDownTimer的理解(countdowntomars)
-
CountDownTimer是android开发常用的计时类,按照注释中的说明使用方法如下:kotlin:object:CountDownTimer(30000,1000){...
- 反射为什么性能会很慢?(反射时为什么会越来越长)
-
1.背景前段时间维护一个5、6年前的项目,项目总是在某些功能使用上不尽人意,性能上总是差一些,仔细过了一下代码发现使用了不少封装好的工具类,工具类里面用了好多的反射,反射会影响到执行效率吗?盲猜了一...
- btrace 开源!基于 Systrace 高性能 Trace 工具
-
介绍btrace(又名RheaTrace)是抖音基础技术团队自研的一款高性能AndroidTrace工具,它基于Systrace实现,并针对Systrace不足之处加以改进,核心改进...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- .NET 奇葩问题调试经历之3——使用了grpc通讯类库后,内存一直增长......
- 全局和隐式 using 指令详解(全局命令)
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
- .NET AOT 详解(.net 6 aot)
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
- asar归档解包(游戏arc文件解包)
- 在PyCharm 中免费集成Amazon CodeWhisperer
- 2014年最优秀JavaScript编辑器大盘点
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)