实现热部署指的是在服务不停止的情况下,动态地更新字节码文件到内存中,即:把修复后的类的字节码文件更新到内存中,让类加载器重新加载
背景:修复了一个小bug,比如更改了一行代码,嫌弃重新打包部署太慢,想尽快看到效果
实现方式:
java -jar arthas.jar
启动Arthasjad --source-only 要修改的类的全类名 > 目录/文件名.java
来反编译出源码到java文件mc –c 类加载器的hashcode 目录/文件名.java -d 输出目录
,mc来编译新修改过的这个java文件retransform class文件所在目录/xxx.class
,重新加载新的字节码项目中的服务采用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,有两个注意点:
修改完后,cp回pod再mc编译修改后的java文件,这里有个坑:不加-c,只执行mc 目录/xx.java -d 字节码的输出目录,会报错:
因为编译一个类可能需要其他import的类,此时可先查找下这个类的加载器的hash码:sc -d类全名
重新编译,这次mc加上 -c 类加载器的哈希码:
让类加载器重新加载新编译的字节码:
再jad反编译,看下是否修改成功:
合理!
注意点:
这种方式只是将字节码信息更新到了内存中,程序重启,字节码还是会恢复成就的
使用retransform,前面vi那步不能添加方法或字段
如果你的方法正在被当前线程执行,那更新的动作也会失败
所以,用阿尔萨斯热更新,只是一种应急的手段,比如CICD线出问题了,平时还是正常编译、打包、部署