文章目录
- 1、Arthas实现热部署
- 2、示例
- 3、注意点
1、Arthas实现热部署
实现热部署指的是在服务不停止的情况下,动态地更新字节码文件到内存中,即:把修复后的类的字节码文件更新到内存中,让类加载器重新加载
背景:修复了一个小bug,比如更改了一行代码,嫌弃重新打包部署太慢,想尽快看到效果
实现方式:
- 服务器上(或服务pod里)
java -jar arthas.jar
启动Arthas - 执行:
jad --source-only 要修改的类的全类名 > 目录/文件名.java
来反编译出源码到java文件 - vi修改源码
- 执行:
mc –c 类加载器的hashcode 目录/文件名.java -d 输出目录
,mc来编译新修改过的这个java文件 - 执行:
retransform class文件所在目录/xxx.class
,重新加载新的字节码
2、示例
项目中的服务采用k8s部署,这里以服务A为例,首先将arthas的jar从hostPath拷贝到pod内:
kubectl cp /root/arthas-boot.jar podName:/ -n namespace
启动:
java -jar arthas-boot.jar
//选择PID
反编译要修改的类的源码:
修改java文件的源码,这里容器对应镜像的基础镜像是OpenJDK,没有vi,我先退出阿尔萨斯,cp到hostPath再编辑
kubectl cp podName:xx.java -n namespace /root/xx.java
//kubectl cp报错removing leading /
和从hostPath拷贝到pod不同,从pod到hostPath,有两个注意点:
- hostPath不能是目录,是一个文件,也即不能是/root,而是/root/xx.java
- podName后面的路径不能是绝对路径,而是从容器workdir开始的相对路径
修改完后,cp回pod再mc编译修改后的java文件,这里有个坑:不加-c,只执行mc 目录/xx.java -d 字节码的输出目录,会报错:
因为编译一个类可能需要其他import的类,此时可先查找下这个类的加载器的hash码:sc -d类全名
重新编译,这次mc加上 -c 类加载器的哈希码:
让类加载器重新加载新编译的字节码:
再jad反编译,看下是否修改成功:
合理!
3、注意点
注意点:
-
这种方式只是将字节码信息更新到了内存中,程序重启,字节码还是会恢复成就的
-
使用retransform,前面vi那步不能添加方法或字段
-
如果你的方法正在被当前线程执行,那更新的动作也会失败
-
所以,用阿尔萨斯热更新,只是一种应急的手段,比如CICD线出问题了,平时还是正常编译、打包、部署