springboot线上热更新_线上调试BUG,就用阿里的这款诊断神器

本文介绍了阿里开源的Java诊断工具Arthas,它能实现线上项目的热更新和调试。文章详细阐述了Arthas的安装步骤、常用命令如dashboard、thread、sysprop、sysenv、logger、sc、sm、jad、mc、redefine、monitor和watch,并通过实例展示了如何在线上环境中热更新Spring Boot应用。
摘要由CSDN通过智能技术生成
4eca17ea18a19bcf3de54179da82c734.png

摘要

线上项目遇到问题无法调试,线下又无法重现,难道只能加日志再重新发布么?有了这款神器,既可以线上调试,又可以实现热修复,推荐给大家!

Arthas 简介

Arthas是Alibaba开源的Java诊断工具,深受开发者喜爱。它采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

安装

为了还原一个真实的线上环境,我们将通过Arthas来对Docker容器中的Java程序进行诊断。

  • 使用arthas-boot,下载对应jar包,下载地址:alibaba.github.io/arthas/arth…
  • 将我们的Spring Boot应用mall-tiny-arthas使用Docker容器的方式启动起来,打包和运行脚本在项目的srcmaindocker目录下;
  • 将arthas-boot.jar拷贝到我们应用容器的目录下;
docker container cp arthas-boot.jar mall-tiny-arthas:/复制代码
  • 进入容器并启动arthas-boot,直接当做jar包启动即可;
docker exec -it mall-tiny-arthas /bin/bashjava -jar arthas-boot.jar复制代码
  • 启动成功后,选择当前需要诊断的Java程序的序列号,这里是1,就可以开始诊断了;
9beacec76a244ec1c6918ade40c6eb7f.png
  • 期间会下载一些所需的文件,完成后控制台打印信息如下,至此Arthas就安装启动完成了。
23af5936714084eeaff40898252e4117.png

常用命令

我们先来介绍一些Arthas的常用命令,会结合实际应用来讲解,带大家了解下Arthas的使用。

dashboard

使用dashboard命令可以显示当前系统的实时数据面板,包括线程信息、JVM内存信息及JVM运行时参数。

4a44c6476c042640602422f3836c285f.png

thread

查看当前线程信息,查看线程的堆栈,可以找出当前最占CPU的线程。

c7975065faa1eb2a19b1449f924b9d6c.png

常用命令:

# 打印当前最忙的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配置。

d5a012d62e3004f263ed965db4adfb61.png

logger

使用logger命令可以查看日志信息,并改变日志级别,这个命令非常有用。

比如我们在生产环境上一般是不会打印DEBUG级别的日志的,当我们在线上排查问题时可以临时开启DEBUG级别的日志,帮助我们排查问题,下面介绍下如何操作。

  • 我们的应用默认使用的是INFO级别的日志,使用logger命令可以查看;
1114f4fd61a491a8c0c7f59075bce79a.png
  • 使用如下命令改变日志级别为DEBUG,需要使用-c参数指定类加载器的HASH值;
logger -c 21b8d17c --name ROOT --level debug复制代码
  • 再使用logger命令查看,发现ROOT级别日志已经更改;
b2b3d653b663a1ab36bff7b55bc402df.png
  • 使用docker logs -f mall-tiny-arthas命令查看容器日志,发现已经打印了DEBUG级别的日志;
4ec646271057b0eca59df5cdf3c82966.png
  • 查看完日志以后记得要把日志级别再调回INFO级别。
logger -c 21b8d17c --name ROOT --level info复制代码

sc

查看JVM已加载的类信息,Search-Class的简写,搜索出所有已经加载到 JVM 中的类信息。

  • 搜索com.macro.mall包下所有的类;
sc com.macro.mall.*复制代码
e626eefd451f37aa5e0e2c5df36a2d58.png
  • 打印类的详细信息,加入-d参数并指定全限定类名;
sc -d com.macro.mall.tiny.common.api.CommonResult复制代码
328d1d9d7d6ad477f7b64b9dcb33de3d.png
  • 打印出类的Field信息,使用-f参数。
sc -d -f com.macro.mall.tiny.common.api.CommonResult复制代码
b9261609208fba656e3d36096b65c711.png

sm

查看已加载类的方法信息,Search-Method的简写,搜索出所有已经加载的类的方法信息。

  • 查看类中的所有方法;
sm com.macro.mall.tiny.common.api.CommonResult复制代码
f81a1de345eee6191377c7d47618b2a7.png
  • 查看指定方法信息,使用-d参数并指定方法名称;
sm -d com.macro.mall.tiny.common.api.CommonResult getCode复制代码
9a72190752b7d90c9ad0e08d3ac7d907.png

jad

反编译已加载类的源码,觉得线上代码和预期不一致,可以反编译看看。

  • 查看启动类的相关信息,默认会带有ClassLoader信息;
jad com.macro.mall.tiny.MallTinyApplication复制代码
180753e3f2b5316b30b96894ffdca2a9.png
  • 使用--source-only参数可以只打印类信息。
jad --source-only com.macro.mall.tiny.MallTinyApplication复制代码
27607173944417799fbcf453c94d6768.png

mc

内存编译器,Memory Compiler的缩写,编译.java文件生成.class。

redefine

加载外部的.class文件,覆盖掉 JVM中已经加载的类。

monitor

实时监控方法执行信息,可以查看方法执行成功此时、失败次数、平均耗时等信息。

monitor -c 5 com.macro.mall.tiny.controller.PmsBrandController listBrand复制代码
71a8aee64660cdb700c78a8f771b2a63.png

watch

方法执行数据观测,可以观察方法执行过程中的参数和返回值。

使用如下命令观察方法执行参数和返回值,-x表示结果属性遍历深度。

watch com.macro.mall.tiny.service.impl.PmsBrandServiceImpl listBrand "{params,returnObj}" -x 2复制代码
b4fc2c2abc6d58039d18de912e17c6eb.png

热更新

尽管在线上环境热更代码并不是一个很好的行为,但有的时候我们真的很需要热更代码。下面介绍下如何使用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 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 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复制代码
483dc73c13bb53cbb0e4228870fb62ab.png
  • 之后使用内存编译器把改.java文件编译成.class文件,注意需要使用-c指定类加载器;
mc -c 21b8d17c /tmp/PmsBrandController.java -d /tmp复制代码
78859d76dc734b9c9f497dc36c526ec0.png
  • 最后使用redefine命令加载.class文件,将原来加载的类覆盖掉;
redefine -c 21b8d17c /tmp/com/macro/mall/tiny/controller/PmsBrandController.class复制代码
d67b27c56c5759c942900edef1085f87.png
  • 我们再次调用接口进行测试,发现已经返回了预期的结果,调用地址:http://192.168.3.101:8088/brand/0
{  "code": 200,  "message": "操作成功",  "data": null}复制代码

参考资料

官方文档:alibaba.github.io/arthas/


作者:MacroZheng
链接:https://juejin.im/post/5f017dd56fb9a07e953df64b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值