SpringBoot实战电商项目mall(35k+star)地址:github.com/macrozheng/…java
线上项目遇到问题没法调试,线下又没法重现,难道只能加日志再从新发布么?有了这款神器,既能够线上调试,又能够实现热修复,推荐给你们!git
Arthas是Alibaba开源的Java诊断工具,深受开发者喜好。它采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。github
为了还原一个真实的线上环境,咱们将经过Arthas来对Docker容器中的Java程序进行诊断。docker
使用arthas-boot
,下载对应jar包,下载地址:alibaba.github.io/arthas/arth…json
将咱们的Spring Boot应用mall-tiny-arthas
使用Docker容器的方式启动起来,打包和运行脚本在项目的src\main\docker
目录下;api
将arthas-boot.jar
拷贝到咱们应用容器的\
目录下;bash
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
复制代码
1
,就能够开始诊断了;咱们先来介绍一些Arthas的经常使用命令,会结合实际应用来说解,带你们了解下Arthas的使用。服务器
使用dashboard
命令能够显示当前系统的实时数据面板,包括线程信息、JVM内存信息及JVM运行时参数。app
查看当前线程信息,查看线程的堆栈,能够找出当前最占CPU的线程。工具
经常使用命令:
# 打印当前最忙的3个线程的堆栈信息
thread -n 3
# 查看ID为1都线程的堆栈信息
thread 1
# 找出当前阻塞其余线程的线程
thread -b
# 查看指定状态的线程
thread -state WAITING
复制代码
查看当前JVM的系统属性,好比当容器时区与宿主机不一致时,可使用以下命令查看时区信息。
sysprop |grep timezone
复制代码
user.timezone Asia/Shanghai
复制代码
查看JVM的环境属性,好比查看下咱们当前启用的是什么环境的Spring Boot配置。
使用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
复制代码
查看JVM已加载的类信息,Search-Class
的简写,搜索出全部已经加载到 JVM 中的类信息。
com.macro.mall
包下全部的类;sc com.macro.mall.*
复制代码
-d
参数并指定全限定类名;sc -d com.macro.mall.tiny.common.api.CommonResult
复制代码
-f
参数。sc -d -f com.macro.mall.tiny.common.api.CommonResult
复制代码
查看已加载类的方法信息,Search-Method
的简写,搜索出全部已经加载的类的方法信息。
sm com.macro.mall.tiny.common.api.CommonResult
复制代码
-d
参数并指定方法名称;sm -d com.macro.mall.tiny.common.api.CommonResult getCode
复制代码
反编译已加载类的源码,以为线上代码和预期不一致,能够反编译看看。
ClassLoader
信息;jad com.macro.mall.tiny.MallTinyApplication
复制代码
--source-only
参数能够只打印类信息。jad --source-only com.macro.mall.tiny.MallTinyApplication
复制代码
内存编译器,Memory Compiler
的缩写,编译.java
文件生成.class
。
加载外部的.class
文件,覆盖掉 JVM中已经加载的类。
实时监控方法执行信息,能够查看方法执行成功此时、失败次数、平均耗时等信息。
monitor -c 5 com.macro.mall.tiny.controller.PmsBrandController listBrand
复制代码
方法执行数据观测,能够观察方法执行过程当中的参数和返回值。
使用以下命令观察方法执行参数和返回值,-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));
}
}
复制代码
{
"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/
复制代码
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
复制代码
{
"code": 200,
"message": "操做成功",
"data": null
}
复制代码
官方文档:alibaba.github.io/arthas/
mall项目全套学习教程连载中,关注公众号第一时间获取。