关于服务治理:Sermant-的整体流程学习梳理

53次阅读

共计 4377 个字符,预计需要花费 11 分钟才能阅读完成。

作者:用友汽车信息科技(上海)有限公司 刘亚洲 Java 研发工程师

一、sermant 架构

Sermant 整体架构包含 Sermant Agent、Sermant Backend、Sermant Injector、动静配置核心等组件。其中 Sermant Agent 是提供字节码加强根底能力及各类服务治理能力的外围组件,Sermant Backend、Sermant Injector、动静配置核心为 Sermant 提供其余能力的配套组件。

二、java agent 和 bytebuddy 组合应用场景

比拟典型的就是 skywalking、sermant、arthas、mockito。如果说 java agent 开了一扇门,那么 bytebuddy 在开的这扇门中关上了一片新的天地。

三、Sermant 的入口

后面咱们说 AgentLauncher 是 java agent 的入口,为什么这么说呢?

<manifestEntries>
    <Premain-Class>com.huaweicloud.sermant.premain.AgentLauncher</Premain-Class>
    <Agent-Class>com.huaweicloud.sermant.premain.AgentLauncher</Agent-Class>
    <Can-Redefine-Classes>true</Can-Redefine-Classes>
    <Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>

答案能够从 pom.xml 中找到答案,这里能够看到基于 Premain-Class 和 Agent-Class 的两个类都指向了 AgentLauncher 这个类。因而咱们能够十分确认的必定它就是 javaagent 入口类。相似于 java 程序有一个 main 的执行入口,而 java agent 有一个本人的入口类 premain。

因而能够看到它的入口执行 main:

/**
 * premain
 *
 * @param agentArgs premain 启动时携带的参数
 * @param instrumentation 本次启动应用的 instrumentation
 */
public static void premain(String agentArgs, Instrumentation instrumentation) {launchAgent(agentArgs, instrumentation, false);
}

/**
 * agentmain
 *
 * @param agentArgs agentmain 启动时携带的参数
 * @param instrumentation 本次启动应用的 instrumentation
 */
public static void agentmain(String agentArgs, Instrumentation instrumentation) {launchAgent(agentArgs, instrumentation, true);
}

基于 premain 模式的和基于 agent 模式,区别在于是否为 isDynamic。从这里咱们能够看到这里提出了两个类值得咱们去关注:
AgentCoreEntrance、CommandProcessor,也即 sermant 这个我的项目的两个重点类。

更多须要理解的,能够参考 byte-buddy 这个开源我的项目。

四、入口办法执行的全流程

五、spi 的加载过程

启动外围服务的过程是 spi 的加载过程,此时会初始化所有的服务。也即咱们看到的所有服务会在此时会做一个启动的操作,同时还会启动事件:

service.start();
collectServiceStartEvent(startServiceArray.toString());

其实这个两个办法也做了很多事件。
启动服务做的事件:

collectServiceStartEvent 则调用 netty 客户端向 netty 服务端发送数据。到服务端后,服务端进行数据处理,其收集的信息提供给 backend 模块不便后盾展现查看。

六、以标签路由为例 PluginService 中扩大插件初始化

除此之外,还有一批实现了 BaseService 接口的,也即 PluginService 扩大插件服务基类,以标签路由为例,能够看你的其初始化的整个过程。

七、install 的过程
同时咱们能够看到 install 对应的 process 办法也是执行它的办法:

public ResettableClassFileTransformer install(Instrumentation instrumentation) {AgentBuilder builder = new Default().disableClassFormatChanges();
      // 遍历 actions
      for (BuilderAction action : actions) {builder = action.process(builder);
      }
      // 执行安装操作,此时交给 bytebuddy
      return builder.installOn(instrumentation);
  }

从入参中的 Instrumentation,咱们往回看:ByteEnhanceManager.init(instrumentation)

这个办法外面定义了 action 的程序。

public static void init(Instrumentation instrumentation) {
       instrumentationCache = instrumentation;
       builder = BufferedAgentBuilder.build();

       // 初始化实现后,新增 Action 用于增加框架间接引入的字节码加强
       enhanceForFramework();}

执行上面的过程:

咱们依据下面的增加程序,来看初始化插件的程序:

public static void enhanceDynamicPlugin(Plugin plugin) {if (!plugin.isDynamic()) {return;}
        // 获取形容信息
        List<PluginDescription> plugins = PluginCollector.getDescriptions(plugin);
        // 增加插件,而后执行安装操作
        ResettableClassFileTransformer resettableClassFileTransformer = BufferedAgentBuilder.build()
                .addPlugins(plugins).install(instrumentationCache);
        plugin.setClassFileTransformer(resettableClassFileTransformer);
    }

从援用上看,PluginSystemEntrance.initialize(isDynamic)中援用了这个办法。

 能够看到这里的增加插件,能够了解为自定义的插件。

从 sermant 官网,咱们能够晓得:定义自定义插件,须要实现 PluginDeclarer 这个接口。也即从这里能够看到也即自定义的插件:

 /**
     * 从插件收集器中获取所有插件申明器
     *
     * @param classLoader 类加载器
     * @return 插件申明器集
     */
    private static List<? extends PluginDeclarer> getDeclarers(ClassLoader classLoader) {final List<PluginDeclarer> declares = new ArrayList<>();
        for (PluginDeclarer declarer : loadDeclarers(classLoader)) {if (declarer.isEnabled()) {declares.add(declarer);
            }
        }
        return declares;
    }

有了插件,就能够进行安装操作。

依照这个程序,能够看到对应的 action.process(builder)外面也执行了对应的构建办法。实现构建后,执行 installOn 办法。

实现装置工作后,依据装置前 spi 的加强实现,而后执行上游服务拦挡加强,从而实现精准筛选工作。

八、以标签路由上游拦挡解决为例

能够看到标签路由对应的几个代表性的 Declarer:
NopInstanceFilterDeclarer、LoadBalancerDeclarer、BaseLoadBalancerDeclarer、ServiceInstanceListSupplierDeclarer 等。

对应的拦截器 Interceptor:
NopInstanceFilterInterceptor、LoadBalancerInterceptor、BaseLoadBalancerInterceptor、ServiceInstanceListSupplierInterceptor。

两者互相呼应。

LaneServiceImpl 和 LoadBalancerServiceImpl 是基于 sermant 框架的插件服务 spi 做的实现。

LaneServiceImpl 和 RouteRequestTagHandler 是和路由能力相干的,LaneServiceImpl 和 LaneRequestTagHandler 是和染色能力相干的。RouteRequestTagHandler 用来拦挡并存储调用过程中的标签,FlowRouteHandler 和 TagRouteHandler 是在路由抉择上游实例时做的筛选过程。

上游拦挡办法会通过 BaseLoadBalancerInterceptor 到 loadBalancerService.getTargetInstances(serviceId, instances, requestData),最终到 HandlerChainEntry.INSTANCE.process(targetName, instances, requestData),基于责任链模式执行解决。目前次要有两种形式:FlowRouteHandler 和 TagRouteHandler。

这外面只是简略的介绍了整体的流程,具体细节的内容,还须要本人多实际。同时 sermant 大量应用了 java agent 的内容。

因为自己的局限性,有不妥的中央,还望批评指正!
 
参考:
sermant 官网:https://sermant.io/zh/
sermant 开源地址:https://github.com/huaweicloud/Sermant
byte-buddy 开源地址:https://github.com/raphw/byte-buddy

正文完
 0