解析Sermant热插拔能力:服务运行时动态挂载JavaAgent和插件

💡 原文中文,约4000字,阅读约需10分钟。
📝

内容提要

本文介绍了Sermant的动态接入能力,通过JavaAgent的静态加载和动态加载方式实现服务治理能力的接入。文章分析了动态加载方式的局限性,并解决了动态安装过程中的重转换和插件安装卸载时的互相影响问题。Sermant通过字节码增强锁和类文件转换器实现了不重复执行字节码增强和保证其他插件不失效的机制。文章总结了Sermant的热插拔能力的核心机制,并鼓励开发者和使用者参考官方文档和使用手册,期待更多的热插拔能力的分享。

🔎

延伸解读

动态加载的固有局限

Sermant 1.2.0 起支持服务不停机安装卸载,但动态加载方式本身存在限制:重转换不能新增、删除或重命名字段和方法,不能更改方法签名,也不能修改类的继承关系,还不能增强内存与资源文件中字节码不一致的类。这些限制源于 Instrumentation API 的规范,并非 Sermant 独有。因此,动态接入虽灵活,但并非所有场景都适用,选型时需权衡。

字节码增强锁如何避免重复增强

Sermant 为每个目标方法维护一个 AdviceKey 锁(由类名、方法哈希和类加载器组成)。动态安装插件触发类转换时,转换器尝试获取该锁:若成功,说明方法未被增强,则执行字节码增强并将拦截器加入列表;若失败,说明已被增强,则仅添加拦截器,不重复增强。这一机制避免了多插件安装时的重复字节码操作,减少了无谓的性能损耗。

插件卸载时如何保障其他插件不失效

当某个插件卸载时,它会释放自身持有的 AdviceKey 锁,并触发目标类的重转换。此时,其他未卸载插件对应的类文件转换器会再次被唤醒,重新经历获取锁和字节码增强的流程。这样,只要还有插件需要增强该目标方法,就能重新获得锁并完成增强,不会因为方法交集而导致其他插件能力失效。这一设计确保了插件卸载的隔离性。

❓

Q&A

Sermant从哪个版本开始支持服务不停机动态安装和卸载?

从1.2.0版本开始,Sermant实现了在服务不停机状态下进行安装和卸载的能力。

JavaAgent的静态加载和动态加载有什么区别?

静态加载利用premain在应用程序启动时加载JavaAgent,会在执行任何代码之前修改字节码;动态加载利用agentmain通过Java Attach API将JavaAgent加载到已运行的JVM中,通过字节码重转换在运行时修改字节码。

动态加载JavaAgent有哪些局限性?

动态加载通过类重转换触发字节码增强,不能修改类的继承关系,不能为类添加静态代码块,不能增强内存中和资源文件中字节码不一致的类。

Sermant如何保证动态安装插件时不重复执行字节码增强?

Sermant维护了针对目标方法的字节码增强锁(AdviceKey锁),类文件转换器触发时尝试获取锁,能获取则执行字节码增强,不能获取则只将拦截器放入列表,不执行增强,从而避免重复增强。

Sermant在插件卸载时如何确保其他插件不失效?

插件卸载时释放自身持有的AdviceKey锁,触发目标类重转换,其他插件的类文件转换器会再次触发,获取锁并执行字节码增强,从而保证其他插件能力不失效。

Sermant是什么?它基于什么技术?

Sermant是基于Java字节码增强技术的无代理服务网格,利用Java字节码增强技术为宿主应用程序非侵入地提供服务治理功能。

🏷️

标签

➡️

继续阅读