Sermant类隔离架构:解决JavaAgent场景类冲突的实践

这篇具有很好参考价值的文章主要介绍了Sermant类隔离架构:解决JavaAgent场景类冲突的实践。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文分享自华为云社区《Sermant类隔离架构解析——解决JavaAgent场景类冲突的实践》,作者:华为云开源。

Sermant是基于Java字节码增强技术的无代理服务网格,其利用Java字节码增强技术为宿主应用程序提供服务治理功能。因深知JavaAgent场景中类冲突问题会造成的影响,Sermant在设计之初便为此规划了全面的类隔离架构。经历多次迭代,如今Sermant的类隔离架构已可以轻松的应对各种复杂的类加载环境。

一、JavaAgent场景为什么要注意类冲突问题?

类冲突问题并非仅存在于JavaAgent场景中,在Java场景中一直都存在,该问题通常会导致运行时触发NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError等异常。

从使用场景来看,基于JavaAgent技术所实现的工具,往往用于监控、治理等场景,并非企业核心业务程序。如果在使用时引入类冲突问题,可能会造成核心业务程序故障,得不偿失,所以避免向核心业务程序引入类冲突是一个JavaAgent工具的基本要求。

还有一个重要原因是在Java应用中可以于开发态采用依赖的升降级、统一依赖架构治理等手段解决该问题。但基于JavaAgent技术实现的工具作用于运行态,无法在开发态就和需要被增强的Java应用进行统一的依赖管理,所以引入类冲突问题的可能性更大。

二、JavaAgent场景如何解决该问题?

无论是在Java应用中,还是在JavaAgent场景,修复类冲突的逻辑都是一致的,就是避免引入会冲突的类。不同点在于基于JavaAgent技术实现的各式各样的工具,往往都具有业务无关性,在设计和实现之初,并不会为特定的Java应用类型而定制。对于JavaAgent程序而言,需要被字节码增强的应用即是黑盒,所以无法像Java应用那样去梳理依赖结构,排除、升级依赖项,统一进行依赖架构治理。并且JavaAgent往往在运行时使用,所以只能通过保障依赖绝对隔离的方式来避免引入冲突。

为何会产生类冲突,本文重点不在此,简单讲是因为我们在Java中因为重复引入传递依赖、类的加载顺序无法控制等问题,导致引入了相同【类加载器和全限定类名(Fully Qualified Class Name)都相同】但又表现不同【因为类版本不同而导致的类逻辑不一致】的类。所以为了避免冲突,我们就需要避免在运行时引入相同的类,如何让JavaAgent引入的类和宿主完全不相同,从全限定类名和类加载器下手才是根本:

  • 基于maven shade plugin进行类隔离

该插件是Maven提供用于构建打包的插件,通过maven-shade-plugin的‘Relocating Classes’能力,来修改某些类的全限定类名。

此方法的原理便是通过改变全限定类名来让JavaAgent引入的类和Java程序的类完全不可能出现相同的情况,从根本上避免类冲突。但是我们在使用一种框架,或者使用一种产品时,往往约定要优于配置,基于maven-shade-plugin通过配置去改变全限定类名并不是一个简单的办法,在使用时就需要针对JavaAgent所涉及依赖进行梳理,在maven-shade-plugin中进行配置,并且需要在每次依赖变更后重新筛查。对持续迭代极不友好。

采用上述方法也对Debug造成阻碍,在Debug过程中被重定向的类的断点将不可达,严重降低调试效率。

  • 基于类加载机制进行类隔离

基于maven-shade-plugin修改全限定类名往往用来解决单点的类冲突问题,虽然也能做到将JavaAgent所引入类完全隔离,但并不是一个好的解决方案。

基于类冲突原理,我们还可以通过限制两个相同全限定类名的类的加载器来让其不同,如Tomcat那样,通过自定义类加载器破坏Java的双亲委派原则,来隔离JavaAgent引入的类。这样既避免了繁重的配置,也避免了依赖变更而带来的影响。但也有其弊端,在JavaAgent场景中往往会利用到Java应用程序的类,所以基于类加载器的隔离机制,往往就让开发者只能通过反射等操作完成此类逻辑,这会对性能和开发效率产生不良影响。

三、Sermant如何做?

Sermant是基于Java字节码增强技术的无代理服务网格,不仅是一个开箱即用的服务治理工具,也同样是一个易用的服务治理能力开发框架。

“把简单留给别人,把麻烦留给自己!”

Sermant从设计之初就遵循上述重要原则,并规划了全方面的类隔离架构,利用Java的类加载机制对自身各模块做了充分类隔离,让使用者和开发者无需考虑因使用JavaAgent而导致类冲突问题,并且也针对开发者的使用场景做了优化,可以在开发中无缝使用被增强Java程序的类,避免因反射等行为带来的不利影响。Sermant是如何实现的呢,下文将对Sermant类隔离架构进行详细解析。

1) Sermant的类隔离架构解析

如上文所说,Sermant不仅是个开箱即用的服务网格,也同样是一个易用的服务治理能力开发框架,服务治理能力是多样的包括但不限于流量治理、可用性治理、安全治理等,所以Sermant采用插件化的架构来让用户能更灵活的接入和开发服务治理能力。

在Sermant的整体架构下,我们不仅需要保证不向宿主服务引入类冲突问题,避免在开箱即用时对宿主服务造成负面影响,同时也需要保障框架与插件、插件与插件之间不会引入类冲突问题,避免插件开发者因为和其他服务治理插件产生类冲突问题而苦恼,所以Sermant设计了如下类隔离结构:

  • SermantClassLoader,破坏双亲委派,用于加载Sermant框架核心逻辑,并在AppClassLoader下隔离出Sermant的类加载模型。避免受到宿主服务自身复杂类加载结构的影响,减少应对不同类加载结构服务的适配需求。
  • FrameworkClassLoader,破坏双亲委派,主要作用是隔离Sermant核心能力所引入的三方依赖,避免向宿主服务及服务治理插件引入类冲突问题。目前的主要场景 ①用于隔离Sermant的日志系统,避免对宿主服务的日志系统产生影响 ②隔离Sermant框架的核心服务(心跳、动态配置、统一消息网关)所需三方依赖。
  • PluginClassLoader,遵循双亲委派,主要用于隔离Sermant各服务治理插件,避免不同服务治理插件之间产生类冲突问题。
  • ServiceClassLoader,破坏双亲委派,主要用于隔离插件中的依赖,通过该类加载器加载插件服务的相关lib(插件服务会在插件加载时被Sermant初始化),开发者可任意引入三方依赖,无需关心对插件主逻辑的影响。

其中的PluginClassloader和ServiceClassloader不仅在类隔离中起到至关重要的作用,更是一种长远的考虑,为每个插件设计独立的类加载器,使得Sermant可以平滑的进行插件动态安装&卸载以及插件热更新。

2) 插件隔离的特殊之处

在上文中所述类隔离架构中,可以看到一处特别的逻辑(红框处),这也是Sermant中PluginClassLoader(插件类加载器)的特殊之处,在实际使用过程中,每个插件类加载器会在其中为每个线程维护一个局部的类加载器(localLoader)。

PluginClassLoader遵循双亲委派,在类加载过程中先委派SermantClassLoader加载Sermant的核心类,再通过自身加载插件类,当需要使用宿主服务的类时,则会委托局部类加载器(其Parent可以是任何类加载器,不局限于图中所指示)进行加载。用于让字节码增强的切面逻辑(Sermant拦截器)可以获取到宿主服务所使用的类,这有利于服务治理场景,其逻辑如下图所示:

通过重写类加载器loadClass逻辑,在执行Sermant拦截器时,配置一个局部的类加载环境,让Sermant拦截器中的逻辑可以顺利的使用宿主服务加载的类,这样开发服务治理插件时无需通过反射获取宿主服务的类,从而提升服务治理能力的开发效率和最终运行时的性能,同时还避免了宿主服务和服务治理插件的类冲突。

(代码实现可以在开源仓库进行查看:)

3) 实战效果如何

因接入JavaAgent而导致的依赖冲突、类冲突问题乃是业界通病,但如果有Sermant的类加载机制加持,该问题则可从根源避免,不再让广大JavaAgent的使用者和开发者深受其害!

《拜托,别在 agent 中依赖 fastjson 了》所述案例,是一个因JavaAgent而产生的依赖冲突问题的典型场景,其应用通过AppClassLoader加载到了Agent中fastjson的类FastJsonHttpMessageConverter, 该类依赖spring-web.jar的类GenericHttpMessageConverter,但由于AppClassLoader的搜索路径中并没有spring-web.jar(fastjson通过provide方式引入),最终加载类失败。

但如基于Sermant开发则不会产生该问题,基于Sermant开发JavaAgent和Spring应用一起运行时的类隔离架构如下:

在此类加载器的结构下,有两个关键的不同:

  1. 由于Sermant改变了类加载的结构,通过Agent引入的fastjson已不在AppClassLoader的搜索路径中,因此Agent中的FastJsonHttpMessageConverter类不再会被Spring应用通过AppClassLoader加载到,从根源上避免了文中所触发的类冲突问题。
  2. 当运行时若Agent需要使用spring-web的类GenericHttpMessageConverter时,则可通过Sermant提供的局部类加载环境成功通过LaunchedUrlClassloader成功从Spring应用中获取。

正是因为此两点差异,让基于Sermant开发的能力可以在和应用之间进行类隔离,避免通过JavaAgent引入类冲突问题,同时可以在运行时使用应用所引入的类。

四、总结

Sermant是基于Java字节码增强技术的无代理服务网格,其利用Java字节码增强技术为宿主应用程序提供服务治理功能。因深知JavaAgent场景中类冲突问题会造成的影响,Sermant在设计之初便为此规划了全面的类隔离架构。经历多次迭代,如今Sermant的类隔离架构已可以轻松的应对各种复杂的类加载环境。

除了保证类隔离,Sermant作为服务网格需要重点关注自身的服务治理能力对宿主服务带来的性能影响,所以也通过独有设计避免因为过度隔离带来的性能损耗。同时Sermant还在构建开放的服务治理插件开发生态,并提供高效的服务治理能力开发框架。在类隔离设计时也考虑到了易用性、开发效率提升等方面的问题。并未因为类隔离机制的存在,而降低开发的效率,增大学习曲线的陡峭程度。

Sermant 作为专注于服务治理领域的字节码增强框架,致力于提供高性能、可扩展、易接入、功能丰富的服务治理体验,并会在每个版本中做好性能、功能、体验的看护,广泛欢迎大家的加入。

  • Sermant 官网:https://sermant.io
  • GitHub 仓库地址:https://github.com/huaweicloud/Sermant

 文章来源地址https://www.toymoban.com/news/detail-700189.html

点击关注,第一时间了解华为云新鲜技术~

 

到了这里,关于Sermant类隔离架构:解决JavaAgent场景类冲突的实践的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 云计算:从基础架构原理到最佳实践之:云计算多租户管理与隔离

    作者:禅与计算机程序设计艺术 云计算作为一种新的计算模式和服务方式已经逐渐成为大众的生活的一部分,它无处不在。其最大的好处就是能将更多的计算、存储、网络等资源集中到一个平台上,提供给用户更多的弹性、可靠以及更高的性能。但是同时也带来了新的复杂性

    2024年04月10日
    浏览(39)
  • 哪些设备可以隔离冲突域哪些可以隔离广播域,哪些设备什么都无法隔离

    在计算机网络中,有两个概念与网络隔离相关:冲突域和广播域。冲突域表示一个物理网络中共享相同带宽的设备集合,而广播域是指网络中一个广播消息(如ARP请求)传播的范围。以下是一些设备和技术,它们对冲突域和广播域的隔离具有影响: 隔离冲突域的设备和技术:

    2024年02月05日
    浏览(36)
  • 云原生场景下高可用架构的最佳实践

    作者:刘佳旭(花名:佳旭),阿里云容器服务技术专家 随着云原生技术的快速发展以及在企业 IT 领域的深入应用,云原生场景下的高可用架构,对于企业服务的可用性、稳定性、安全性越发重要。通过合理的架构设计和云平台的技术支持,云原生高可用架构可以提供高可

    2024年02月07日
    浏览(90)
  • flink类加载器原理与隔离(flink jar包冲突)

    本文是转载自袋鼠云公众号的文章 不知道大家有没有遇到过,flink发布任务遇到一些奇奇怪怪的报错,很奇怪的某个类就开始报错,一步一步点击去查看,发现不知道是哪个类包的那个类在报错,其实这种情况很有可能就是jar包版本冲突。 首先为大家介绍一下Java类加载器解

    2024年02月22日
    浏览(34)
  • 数据仓库内容分享(十七):Doris实践分享:它做了哪些架构优化和场景优化?

    Apache Doris是一款开源的实时数据仓库,由百度旗下的技术团队开发。它具有高性能、高可靠性、易扩展等特点,能够满足大规模数据实时查询和分析的需求。目前,Apache Doris已经成为国内外众多企业的首选数据仓库解决方案,包括阿里巴巴、美团、京东、滴滴等知名企业。

    2024年02月21日
    浏览(53)
  • 数据库隔离级别:从并发冲突到数据一致性的演进历程

    引言: ​ 数据库隔离级别是现代数据库系统中的重要概念,它决定了多个并发事务之间如何进行隔离,并确保数据的一致性。在数据库系统发展的早期,隔离级别的概念并不明确,开发人员需要自行处理并发冲突和数据不一致性的问题。然而,随着数据库系统的发展和应用需

    2024年02月04日
    浏览(46)
  • 交换机,路由器, 虚拟局域网是如何隔离冲突域和广播域的

    1. 交换机(switch): 隔离冲突域: 交换机在数据链路层工作,每个交换机端口都是一个独立的冲突域。这意味着每个设备连接到交换机的端口上都有其独立的通信媒体,不与其他设备共享。当一个设备向交换机发送数据时,交换机只将数据转发到目标设备的端口,而不是广

    2024年01月17日
    浏览(50)
  • 音视频解决方案(二):直播电商场景最佳实践

    本文介绍使用ZEGO SDK 开发电商场景的小程序,具备音视频直播、IM互动、商品列表推送、美颜等功能,可满足商家多种直播卖货需求,可参考该组件实现自己的需求。 若小程序具备符合live-pusher、live-player的类目,则可以使用live-pusher和live-player,live-room 的isNative属性传入true。

    2024年02月20日
    浏览(50)
  • PHP实践:分布式场景下的Session共享解决方案实现

    🏆作者简介,黑夜开发者,全栈领域新星创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于PHP专栏:PHP进阶实战教程。 🏆另有专栏PHP入门基础教程,希望各位大佬

    2024年02月13日
    浏览(34)
  • 在CSDN学Golang场景化解决方案(微服务架构设计)

    在Golang微服务架构设计中,聚合器(Aggregator)微服务设计模式是一种常见的应用程序体系结构模式。该模式旨在简化客户端与后端微服务之间的通信,并支持更高级别的操作,例如聚合多个后端服务的数据。以下是一个简单的示例: 首先定义一个聚合器微服务: 在main函数中

    2024年02月14日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包