作者:栾文飞 高档软件工程师

一、背景介绍

Sermant是一个主打服务管理范畴的Java Agent结构,在服务管理中难免会有针对事务流量进行解析和处理的进程,此类服务管理才能将会对微服务的服务才能发生一定的功用影响,作为一个依据Java Agent技能做服务管理的结构,咱们需求在保证服务管理才能收效的一起,极小的影响微服务原有的服务功用。

尽管依据Java Agent的服务管理和依据SDK的服务管理在其原理上有所不同,但也避免不了微服务管理进程中发生对微服务原有功用的影响,依据Java Agent服务管理办法的相较于SDK的服务管理办法免去了侵入式的代码开发,是一种运行时技能,所以还需求考虑更多方面功用优化问题,例如在发动时刻,运行时增强功用开销等,本文将以Sermant的SpringBoot 注册插件的功用测验及优化进程为例,分享在Java Agent场景怎么进行更好的功用测验优化及在Java Agent下需求侧重留意的功用圈套。

SpringBoot 注册插件为SpringBoot运用供给服务注册发现才能,可用于在不修改原有代码的前提下快速从ESB架构演进为微服务架构,在该插件中包含针对域名的替换才能,服务注册发现才能,恳求的超时重试等,为架构的成功演进,原有架构中依据域名的恳求调用,将会被依据注册信息的恳求调用(经过该插件的服务注册发现才能,获取服务供给者注册的信息)所取代,如下图所示:

Java Agent场景性能测试分析优化经验分享

在域名处理的进程是必然会参加到调用进程中的,这是服务管理才能对事务功用影响的典型场景。

二、测验计划

众所周知,Java Agent程序和被增强运用运行时同进程,Java Agent程序最重要的是不能对被挂载的运用发生反常影响,导致运用不可用,所以Sermant在运行时的处理功用及稳定性等做多方面的测验考量。在针对微服务进行测验的进程中,咱们往往只需求重视该微服务的功用即可,经过压力测验来检验微服务的服务供给才能,因为服务管理才能并不直接供给服务,咱们更多地需求重视在开启服务管理才能时,对微服务本身服务供给才能的影响,所以咱们在测验计划中需求进行比照测验来评价服务管理才能的好坏。

本对照测验中,咱们经过压力测验让系统达到极限场景(consumer端的CPU现已抵达瓶颈),来剖析带着Sermant并启用服务管理才能时,对运用原有服务供给才能的影响,此处选用两种部署计划

  • 不带着Sermant,依据网关的场景,是架构改造前的运行模式
  • 带着Sermant的场景,是搬迁后的微服务架构运行模式

Java Agent场景性能测试分析优化经验分享

注:在这种比照测验中,依据Java Agent的服务管理只需求对带着Java Agent程序和不带着Java Agent程序的场景进行对照测验即可,无需两套代码进行对照测验。

因为Java Agent程序和被增强运用处于一致进程,资源共享,依据上述两种部署计划进行测验,以不带着Java Agent程序作为测验剖析的对照组,就能够很清晰的看出引进Java Agent程序后发生的影响,并可依据对照结果进行优化,运用于Sermant上,就能够很容易的分分出Sermant的服务管理才能对微服务本身服务供给才能带来的影响。

三、功用剖析

因为需求针对运用建议的恳求经过字节码增量的办法做域名的替换,SpringBoot 注册插件经过对HttpClient、Openfeign、Okhttp等http客户端进行了字节码增强,咱们依据上一章节中的测验计划对该插件供给的服务管理才能进行了测验,下面咱们以HttpClien为例经过CPU火焰图来讲述如安在Java Agent场景下剖析功用瓶颈:

在功用调优进程中,咱们可经过CPU火焰图来剖析功用瓶颈,火焰图能够称之为功用问题剖析的”X光”,能够很言必有中的看出在程序运行中哪些代码片段发生了反常的CPU占用。能够参阅《运用火焰图(FlameGraph)剖析程序功用》进行学习,当然,收集CPU火焰图的办法很多,咱们只需求学会怎么看懂火焰图即可。

剖析进程

1. 找到字节码增强逻辑的CPU占用

在剖析进程中,首要需求找到字节码增强时选中的被增强办法(本文场景增强办法为InternalHttpClient::doExecute),字节码增强需求被增强程序的原有办法调用触发,所以也能够很清晰的在CPU火焰图中能够看到,Sermant完成的逻辑调用栈在被增强办法之上,在字节码增强逻辑执行结束后,被增强办法还会继续执行。

Java Agent场景性能测试分析优化经验分享

所以除被增强办法执行的调用栈及CPU时刻片占用外,皆为字节码增强所引进逻辑,在功用优化中需侧重重视。

2. 剖析反常占用

依据CPU火焰图原理,找出字节码增强部分,找出反常占用CPU时刻片的调用栈,并进行程序的优化,如下图所示红框选择部分,皆为字节码增强中引进的逻辑,占用了非常多的CPU时刻片,因为字节码增强程序和被增强程序,这种反常的占用,将会严重影响原程序的功用,在针对Java Agent场景的优化中可侧重优化

Java Agent场景性能测试分析优化经验分享

经过上述进程,咱们能够一望而知的看到咱们经过Java Agent程序引进的CPU额定占用,具体占用原因本文就不一一剖析。

四、功用圈套

依据上述两个章节的测验和剖析办法,在本文的最终,列举出在Java Agent开发进程中经常会遇到的功用圈套,这儿也给出处理办法,能够在开发中留意:

削减反射运用

在字节码增强开发进程中,很多状况下,假如类加载器不同,针对被增强运用的类和办法往往需求经过反射去获取并运用,在咱们的功用剖析中,反射是一个CPU占用的巨大圈套,在有些被BootstrapClassLoader加载的类增强时,甚至反射占用了一个办法调用30%以上的CPU事件片。

下图选中办法中,反射占用该办法调用中的大部分CPU时刻片:

Java Agent场景性能测试分析优化经验分享

但是因为类加载器的限制,有些反射是必须要运用的,咱们也能够经过一定的手法进行优化,比方缓存经过反射获取的类和办法,在字节码增强中,多次触发增强逻辑时削减反射占用CPU时刻片非常有用。

Method method = METHOD_CACHE.get(methodKey);if (method != null) {return Optional.of(method);}method = clazz.getDeclaredMethod(methodName, paramsType);METHOD_CACHE.put(methodKey, method);

经过上述进程优化后,经过火焰图来看,效果是非常显著的:

Java Agent场景性能测试分析优化经验分享

留意字节码增强插桩选择

在做字节码增强时的增强点选择很重要,字节码增强增加Transformer后运行时分为两种状况:

  • transform:针对尚未被类加载器加载的类,假如增加Transformer,在类被加载时就会触发字节码的转化。
  • retransform:针对现已被类加载器加载的类,假如增加了Transformer,则需求被从头加载后再进行字节码的转化。

Java中被BootstrapClassLoader加载的类,假如想要进行字节码增强,就需求运用第二种字节码转化的办法,可想而知,假如从头加载类再进行转化必然没有在类第一次加载时就进行转化的效率高。

除上述原因之外,在增强发动类加载器加载的类时,因为双亲派遣机制的限制(只能向上委托,不能向下委托),往往都是需求很多运用反射(用于调用其他类加载器加载的类)来完成增强逻辑。

Java Agent场景性能测试分析优化经验分享

上文中也讲到,不加控制的运用反射将会经过Java Agent程序严重影响被增强运用的功用,所以在开发Java Agent时,需求谨慎选择增强的类,非必要不增强被发动类加载器加载的类。

上述两点是在Java Agent开发进程中最容易发生的向被增强运用引进的功用圈套,除此之外,Java Agent也是由Java所开发,在开发进程中也需求留意不要引进常见的功用圈套。

结束语

Sermant作为专心于服务管理范畴的字节码增强结构,致力于供给高功用、可扩展、易接入的服务管理体验,并会在每个版本中做好功用、功用、体验的看护,广泛欢迎我们的参加。

Sermant官网:sermant.io

GitHub库房地址:github.com/huaweicloud…

点击重视,第一时刻了解华为云新鲜技能~