• Arthas-好用的代码热更新&服务监控诊断工具


    Arthas介绍

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

    官网:https://arthas.aliyun.com/

    Arthas(阿尔萨斯)能为你做什么?

    1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
    2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
    3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
    4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
    5. 是否有一个全局视角来查看系统的运行状况?
    6. 有什么办法可以监控到 JVM 的实时运行状态?
    7. 怎么快速定位应用的热点,生成火焰图?
    8. 怎样直接从 JVM 内查找某个类的实例?

    Arthas-代码热更新能力

    本文将着重介绍arthas的热更新能力,关于arthas对服务的监控诊断不是本文的重点,想了解如何监控服务可以参考官网

    起因

    一、在开发 -> 测试环境 -> 灰度环境过程中,我们经常会经历bug提出 -> bug修复 -> 重新部署验证 的过程

    二、只是想在代码中添加几条日志打印一下相关信息,却需要重新编译打包重启服务

    以上两种无论是对于简单的bug修复还是新增日志代码,都需要重新编译打包并发送到测试环境重启服务,这个过程十分繁琐,常用的更新方式有以下几种:

    1、IDE将修复好的代码重新编译打包,再通过scp 、 ftp上传到测试环境后重启服务【最不推荐】

    2、将更改后的代码提交到git-hotfix分支上,登录测试环境git -> checkout到hotfix分支,再pull更新代码后,再编译打包重启服务【适合没有使用Jenkins的环境】

    3、将更改后的代码提交到git-hotfix分支上,通过Jenkins部署[拉取分支重新编译打包&运行]

    以上几种虽然都可以实现bug修复和验证,但都需要重新编译打包并且重启服务

    如果我们希望的是无需打包和重启服务,而是直接热更新代码,对于简单的bug实现快速纠错的话,则以上几种都无法实现我们的需求

    此时arthas的热更新能力就排上了用场

    使用

    1、先下载demo-arthas-spring-boot.jardemo-arthas-spring-boot是一个很简单的spring boot应用,源代码:查看

    wget https://github.com/hengyunabc/spring-boot-inside/raw/master/demo-arthas-spring-boot/demo-arthas-spring-boot.jar
    java -jar demo-arthas-spring-boot.jar
    
    • 1
    • 2

    启动:

    image-20221109152258990

    启动之后,可以访问80端口:http://localhost/

    image-20221109152348412

    2、接着我们下载arthas工具

    # 下载arthas
    wget https://arthas.aliyun.com/arthas-boot.jar
    # 启动arthas
    java -jar arthas-boot.jar
    
    • 1
    • 2
    • 3
    • 4

    随后arthas会打印出当前服务器上的java进程供我们选择,此时我们只需要根据不同的进程选择数字后回车即可进入到此进程的交互界面

    image-20221109152539945

    我这里显示的是3,回车后:此时arthas已经连接上此进程服务,可以交互式执行操作

    image-20221109152634051

    这里我们简单实用一些命令来看一下arthas的监控情况:输入dashborad可以查看当前系统的实时数据面板,按Q退出界面

    image-20221109152847143

    输入jvm查看虚拟机信息:

    image-20221109153012476

    这里是简单介绍两个监控命令,arthas内部提供了很多强大的监控命令,详细请参考官网介绍。

    3、热更新

    接下来我们在浏览器输入:http://localhost/user/0,会提示报错:

    Something went wrong: 500 Internal Server Error
    
    • 1

    同时日志会打印错误信息:

    java.lang.IllegalArgumentException: id < 1
    	at com.example.demo.arthas.user.UserController.findUserById(UserController.java:19)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看到报错的代码是在UserController.findUserById函数中,此时我们到arthas的交互界面中输入反编译命令 : jad

    [arthas@115725]$ jad com.example.demo.arthas.user.UserController
    
    • 1

    image-20221109153528258

    可以很明显的看到错误原因位置,那么接下来我要将throw new IllegalArgumentException(“id < 1”); 这行代码注释掉并且更新,该如何操作呢?

    3.1、先将UserController反编译到一个目录下

    # --source-only意思是只将代码打印
    [arthas@115725]$ jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
    
    • 1
    • 2

    3.2、vi 修改 /tmp/UserController.java文件

    image-20221109153855693

    3.3、通过sc命令查找加载UserController的ClassLoader

    由于类的加载过程都是通过其加载器完成,故需要先找到UserController的ClassLoader,后面会用到,可以看到UserController是通过LaunchedURLClassLoader加载的

    [arthas@115725]$ sc -d *UserController | grep class-loader
     class-loader      +-org.springframework.boot.loader.LaunchedURLClassLoader@5b2133b1
    
    • 1
    • 2

    3.4、将改好的/tmp/UserController.java 使用mc(Memory Compiler)命令来编译,并且通过–classLoaderClass参数指定ClassLoader:

    [arthas@115725]$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
    Memory compiler output:
    /tmp/com/example/demo/arthas/user/UserController.class
    Affect(row-cnt:1) cost in 905 ms.
    
    • 1
    • 2
    • 3
    • 4

    此时已经将改好的UserController.java编译到了: /tmp/com/example/demo/arthas/user/UserController.class

    $ ll /tmp/com/example/demo/arthas/user/
    总用量 4
    -rw-rw-r-- 1 bdp bdp 1359 119 16:12 UserController.class
    
    • 1
    • 2
    • 3

    3.5、使用redefine命令重新加载新编译好的UserController.class

    [arthas@115725]$ redefine /tmp/com/example/demo/arthas/user/UserController.class
    redefine success, size: 1, classes:
    com.example.demo.arthas.user.UserController
    
    • 1
    • 2
    • 3

    显示加载成功,我们再反编译jad看一下UserController.class,可以看到已经加载进JVM中了

    image-20221109161635093

    3.6、浏览器再次验证: http://localhost/user/0

    {"id":0,"name":"name0"}
    
    • 1

    至此代码热更新完成,以上步骤看似较多,其实只要使用熟练就可以快速热更新bug。

    小技巧:如果需要修复较复杂的代码,比如需要导入import 类,或者新增函数体等,可以先在IDE中编写代码,随后将.java文件scp到测试环境后使用arthas 热更新即可验证。

  • 相关阅读:
    [附源码]Python计算机毕业设计Django抗疫医疗用品销售平台
    数据库重点总结
    opencv 打开中文路径图报错
    下载 Windows11 23H2 官方系统镜像
    QT+OSG/osgEarth编译之二十六:FontConfig+Qt编译(一套代码、一套框架,跨平台编译,版本:FontConfig-5.1.0)
    nuxt添加aos动效
    [附源码]计算机毕业设计springboot基于人脸识别的社区防疫管理系统
    2022阿里巴巴全球数学竞赛 第4题 虎虎生威(盲盒问题、集卡问题)解决思路
    我奉劝各位程序员。。。保重身体啊!
    页面上下左右滑动事件
  • 原文地址:https://blog.csdn.net/qq_35128600/article/details/127772552