3.微服务灰度发布落地实践(组件灰度增强)

文章目录

  • 前言
  • 调用链示图
    • dubbo服务之间的的调链
    • cloud 服务之间的调用链
  • 网关
  • servlet容器: 标签续传
    • 1.定义插件
    • 2.实现灰度增强拦截
  • 线程池: 标签续传
    • 1.拦截Runnable或Callable,接口增强实现标签续传;
      • Callable 插件定义
      • Runnable 插件定义
      • 拦载Callabl或Runnable构造(可共用)
      • 拦载run或call 方法(可共用)
    • 2.拦截ThreadPoolExecutor, 但是当业务使用Callable或Runnable 时,使用的是lambda表达式时,
      • ThreadPool插件定义
      • ThreadPool公共拦截类
      • execute方法拦截
      • submit方法拦截
  • spring-cloud 服务增强
    • 1. 灰度标签续传
      • Feign htttp 拦载插件定义
      • Feign灰度标签拦截器
      • RestTemplate http 拦截插件定义
      • RestTemplate http 拦截灰度标签续传
    • 2.ribbon灰度路由
      • Rule 插件定义
      • Rule 灰度路由规则拦截改写
  • dubbo服务增强
    • 1. 灰度标签续传
      • 服务消费方ContextFilter插件定义
      • 服务提供方ContextFilter插件定义
      • 服务消费方ContextFilter拦截
      • 服务提供方ContextFilter拦截
    • 2. 灰度路由规则拦截改写
      • 路由插件定义
      • 灰度路由规则拦截改写
  • nacos client增强
    • 插件定义
    • 实例uuid拦截上报
  • eureka client增强
    • 插件定义
    • 实例uuid拦截上报

前言

上一篇介绍,agent基础框架的实现,本篇主要介绍灰度标签在各种组件、协议之间续传,以及路由规则改写;从用户客户端发送请求,到用户收到后端响应信息,整个请求链路会经过各种组件,

调用链示图

dubbo服务之间的的调链

在这里插入图片描述

cloud 服务之间的调用链

在这里插入图片描述

上面展示的组件调用链为: 用户->网关->servlet容器服务->线程池->dubbo服务或cloud服务;这仅展示某一种调用路径,实际环境可能更复杂,有经过cloud或消息队列等等,不再一一列举。

网关

网关交互相对杂复一些,单独开篇

servlet容器: 标签续传

通常web容器服务,都会实现servlet,找到适合的组件接口,

  1. 从http请求头获取灰度标签,并设置到threadLocal,
  2. 请求处理完后,清除该信息;
  3. 分析发现比较合适对HandlerAdapter(不是唯一)进行拦截:

1.定义插件

      public class HandlerAdapterDefine extends ClassEnhancePluginDefine {private static final String CLASS_INTERCEPTOR = "com.dbcat.gray.agent.mvc.HandlerAdapterInterceptor";@Overrideprotected ClassMatch enhanceClass() {return HierarchyMatch.byHierarchyMatch("org.springframework.web.servlet.HandlerAdapter");}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return named("handle").and(takesArguments(3));}@Overridepublic String getMethodsInterceptor() {return CLASS_INTERCEPTOR;}@Overridepublic boolean isOverrideArgs() {return false;}}};}@Overridepublic StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {return new StaticMethodsInterceptPoint[0];}}

2.实现灰度增强拦截

public class HandlerAdapterInterceptor implements InInterceptor, InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result){String routingEnv = getRoutingEnv(allArguments);this.setContext(routingEnv);CounterManager.increaseConsume(ComponentType.MVC,routingEnv);}@Overridepublic Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) {//清除threadLocal里的数据this.removeContext();return ret;}private String getRoutingEnv(Object[] allArguments){//从http 请求头或Attribute 获取灰度标签设置到threadLocalObject request =  allArguments[0];Method getHeader = ReflectUtils.getMethod(request, "getHeader", String.class);String env = (String)ReflectUtils.invokeMethod(getHeader, request, X_ENV);if(env != null && !env.trim().equals("")){return env;}Method getAttribute = ReflectUtils.getMethod(request, "getAttribute", String.class);return  (String)ReflectUtils.invokeMethod(getAttribute, request, X_ENV);}
}

这里只是介绍Servlet容器,如果项目实际使用其它类型web容器,也可以用类似的方式对其增强

线程池: 标签续传

服务或消息的路由规则依赖灰度标签,如果业务代码内出现跨线程操作后,则会出现灰度标签断传,从而导致路由错误;针对该问题可以分别对以下线程相关接口或类进行标签续传增强处理:

1.拦截Runnable或Callable,接口增强实现标签续传;

Callable 插件定义

public class CallableDefine extends ClassEnhancePluginDefine {private static final String CALLABLE_CLASS = "java.util.concurrent.Callable";private static final String CALLABLE_CLASS_INTERCEPTOR = "com.dbcat.gray.agent.threading.ThreadingConstructorInterceptor";private static final String CALLABLE_CALL_METHOD_INTERCEPTOR = "com.dbcat.gray.agent.threading.ThreadingMethodInterceptor";@Overrideprotected ClassMatch enhanceClass() {return new ThreadingMatch(CALLABLE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[] {new ConstructorInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getConstructorMatcher() {//拦截构造,切换线程前保存灰度标签到当前Callable实现上return any();}@Overridepublic String getConstructorInterceptor() {return CALLABLE_CLASS_INTERCEPTOR;}}};}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {//拦截call方法return named("call").and(takesArguments(0));}@Overridepublic String getMethodsInterceptor() {return CALLABLE_CALL_METHOD_INTERCEPTOR;}@Overridepublic boolean isOverrideArgs() {return false;}}};}
}

Runnable 插件定义

public class RunnableDefine extends ClassEnhancePluginDefine {private static final String RUNNABLE_CLASS = "java.lang.Runnable";private static final String RUNNABLE_CLASS_INTERCEPTOR = "com.dbcat.gray.agent.threading.ThreadingConstructorInterceptor";private static final String RUNNABLE_RUN_METHOD_INTERCEPTOR = "com.dbcat.gray.agent.threading.ThreadingMethodInterceptor";@Overrideprotected ClassMatch enhanceClass() {return new ThreadingMatch(RUNNABLE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[] {new ConstructorInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getConstructorMatcher() {//拦截构造,切换线程前保存灰度标签到当前Runnable实现上return any();}@Overridepublic String getConstructorInterceptor() {return RUNNABLE_CLASS_INTERCEPTOR;}}};}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[] {new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {//拦载run方法return named("run").and(takesArguments(0));}@Overridepublic String getMethodsInterceptor() {return RUNNABLE_RUN_METHOD_INTERCEPTOR;}@Overridepublic boolean isOverrideArgs() {return false;}}};}
}

拦载Callabl或Runnable构造(可共用)

public class ThreadingConstructorInterceptor implements InInterceptor, InstanceConstructorInterceptor {@Overridepublic void onConstruct(final EnhancedInstance objInst, final Object[] allArguments) {//获取当前线程ThreadLocal里的灰度标签,并保存当前Callable或 Runnable 实现上String env = this.getContext(null);objInst.setGrayDynamicField(env);}
}

拦载run或call 方法(可共用)

public class ThreadingMethodInterceptor implements InInterceptor, InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments,final Class<?>[] argumentsTypes, final MethodInterceptResult result) {String xEnv = (String) objInst.getGrayDynamicField();this.setContext(xEnv);}@Overridepublic Object afterMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments,final Class<?>[] argumentsTypes, final Object ret) {this.removeContext();return ret;}
}

2.拦截ThreadPoolExecutor, 但是当业务使用Callable或Runnable 时,使用的是lambda表达式时,

可以通过拦截ThreadPoolExecutor,增强实现标签续传

ThreadPool插件定义

需要拦截execute和submit方法

public class ThreadPoolExecutorDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPoolExecutor";private static final String INTERCEPT_EXECUTE_METHOD_HANDLE = "com.dbcat.gray.agent.threading.ThreadPoolExecuteMethodInterceptor";private static final String INTERCEPT_SUBMIT_METHOD_HANDLE = "com.dbcat.gray.agent.threading.ThreadPoolSubmitMethodInterceptor";@Overridepublic boolean isBootstrapInstrumentation() {return true;}@Overrideprotected ClassMatch enhanceClass() {return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS), MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS));}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("execute");}@Overridepublic String getMethodsInterceptor() {return INTERCEPT_EXECUTE_METHOD_HANDLE;}@Overridepublic boolean isOverrideArgs() {return true;}},new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("submit");}@Overridepublic String getMethodsInterceptor() {return INTERCEPT_SUBMIT_METHOD_HANDLE;}@Overridepublic boolean isOverrideArgs() {return true;}}};}
}

ThreadPool公共拦截类

public abstract class AbstractThreadPoolInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {if (notToEnhance(allArguments)) {return;}Object wrappedObject = wrap(allArguments[0]);if (wrappedObject != null) {allArguments[0] = wrappedObject;}}public abstract Object wrap(Object param);@Overridepublic Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {return ret;}@Overridepublic void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {}private boolean notToEnhance(Object[] allArguments) {if (allArguments == null || allArguments.length < 1) {return true;}Object argument = allArguments[0];//如果已经被增强过,不必在增强了return argument instanceof EnhancedInstance ;}
}

execute方法拦截

public class ThreadPoolExecuteMethodInterceptor extends AbstractThreadPoolInterceptor {@Overridepublic Object wrap(Object param) {if (param instanceof RunnableWrapper) {return null;}if (param instanceof RunnableFuture) {return null;}if (!(param instanceof Runnable)) {return null;}Runnable runnable = (Runnable) param;return new RunnableWrapper(runnable);}
}

submit方法拦截

public class ThreadPoolSubmitMethodInterceptor extends AbstractThreadPoolInterceptor {@Overridepublic Object wrap(Object param) {if (param instanceof Callable) {Callable callable = (Callable) param;return new CallableWrapper(callable);}if (param instanceof Runnable) {Runnable runnable = (Runnable) param;return new RunnableWrapper(runnable);}return null;}
}

spring-cloud 服务增强

cloud 服务之间的通通http通信的,首先要解决灰度标签在服务之间传递,可以利用http请求头,携带灰度标签;其它次是路由问题,spring-cloud 的远程调用负载是由ribbon实现,只要据灰度标签修改ribbon的路由规则,则可以实现灰度服务路由。

1. 灰度标签续传

分析可能存在通过feign调用或LoadBalance的 RestTemplate 调用服务,所以需要这两种方式的调用进行拦截,通过http请头续传灰度标。

Feign htttp 拦载插件定义

public class FeignTargetPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "feign.Target";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.cloud.FeignRequestContextInterceptor";@Overrideprotected ClassMatch enhanceClass() {return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("apply");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

Feign灰度标签拦截器

public class FeignContextInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {RequestTemplate template = (RequestTemplate) allArguments[0];//续传灰度标签String routingEnv = (String) ServerContextHolder.getData(X_ENV);if (routingEnv != null && !routingEnv.trim().equals("")) {template.header(X_ENV, routingEnv);}}}

RestTemplate http 拦截插件定义

public class ClientHttpRequestInterceptorPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "org.springframework.http.client.ClientHttpRequestInterceptor";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.cloud.HttpRequestContextInterceptor";@Overrideprotected ClassMatch enhanceClass() {return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("intercept");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

RestTemplate http 拦截灰度标签续传

public class HttpRequestContextInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {HttpRequest request = (HttpRequest) allArguments[0];String routingEnv = (String) ServerContextHolder.getData(X_ENV);if (routingEnv != null && !routingEnv.trim().equals("")) {request.getHeaders().set(X_ENV, routingEnv);}}}

2.ribbon灰度路由

Rule 插件定义

public class RulePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "com.netflix.loadbalancer.AbstractLoadBalancerRule";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.cloud.RuleInterceptor";@Overrideprotected ClassMatch enhanceClass() {return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("choose");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

Rule 灰度路由规则拦截改写

public class RuleInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {ZoneAvoidanceRule rule = (ZoneAvoidanceRule) objInst;ILoadBalancer loadBalancer = rule.getLoadBalancer();List<Server> allServers = loadBalancer.getAllServers();if (allServers.isEmpty()) {result.defineReturnValue(null);return;}//据灰度标签,选择相应的服务String env = (String) ServerContextHolder.getData(GrayConstant.X_ENV);ServerSelector serverSelector = CloudServerSelector.build(env, allServers);List<Server> targetServers = serverSelector.selectServers();Server server = doChooseServer(targetServers, rule, allArguments);result.defineReturnValue(server);}private Server doChooseServer(List<Server> targetServers, ZoneAvoidanceRule rule, Object[] allArguments) {if (targetServers.isEmpty()) {return null;}Object loadBalancerKey = allArguments[0];Optional<Server> server = rule.getPredicate().chooseRoundRobinAfterFiltering(targetServers, loadBalancerKey);return server.isPresent() ? server.get() : null;}
}

dubbo服务增强

分析dubbo 源码发布,灰度标签的续传,只要改写ConsumerContextFilter和ContextFilter 两个filter,它们分别是消费的filter和服务提供方的filter;ConsumerContextFilter的作用是消费方上下文件信息通过 rpc的attachment传递给服务提供方;而ContextFilter的作用则是服务提供方将消息传递的上下文从attachment中取出;对灰度路由规则的改写,仅需拦载Router接口的实现即可。

1. 灰度标签续传

服务消费方ContextFilter插件定义


public class ConsumerConextFilterPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "org.apache.dubbo.rpc.filter.ConsumerContextFilter";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.dubbo.ConsumerContextInterceptor";@Overrideprotected ClassMatch enhanceClass() {return NameMatch.byName(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("invoke");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

服务提供方ContextFilter插件定义

public class ProviderContextFilterPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "org.apache.dubbo.rpc.filter.ContextFilter";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.dubbo.ProviderContextInterceptor";@Overrideprotected ClassMatch enhanceClass() {return NameMatch.byName(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("invoke");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

服务消费方ContextFilter拦截

public class ConsumerContextInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) {RpcContext context = RpcContext.getContext();String routingEnv = (String) ServerContextHolder.getData(X_ENV);CounterManager.increaseConsume(DUBBO, routingEnv);if (routingEnv != null && !routingEnv.trim().equals("")) {context.setAttachment(X_ENV, routingEnv);}}
}

服务提供方ContextFilter拦截

public class ProviderContextInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {Invocation invocation = (Invocation) allArguments[1];String routingEnv = invocation.getAttachment(X_ENV);CounterManager.increasePublish(DUBBO, routingEnv);if (routingEnv != null && !routingEnv.trim().equals("")) {ServerContextHolder.setData(X_ENV, routingEnv);}}
}

2. 灰度路由规则拦截改写

路由插件定义

public class AppGrayRouterPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.dubbo.AppGrayRouterInterceptor";@Overrideprotected ClassMatch enhanceClass() {return NameMatch.byName(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[0];}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getMethodsMatcher() {return ElementMatchers.named("route");}@Overridepublic String getMethodsInterceptor() {return INTERCEPTOR_CLASS;}}};}
}

灰度路由规则拦截改写

public class AppGrayRouterInterceptor implements InstanceMethodsAroundInterceptor {@Overridepublic void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result)  {List<Invoker> invokers = (List<Invoker>) allArguments[0];if (invokers.isEmpty()) {result.defineReturnValue(Collections.emptyList());return;}String env = (String) ServerContextHolder.getData(GrayConstant.X_ENV);DubboServerSelector selector = DubboServerSelector.build(env, invokers);List<Invoker> targetInvokers = selector.selectServers();result.defineReturnValue(targetInvokers);}
}

nacos client增强

为了方便 注册中心与灰度管理方及应用实例,统一识别某一个实例,应用在启动时,会动态生产一个实例id, 分别上报到注册中或和灰度发布管理管,所以,如果使用nacos作为注册中心,需在应用启动时,作为元数据上报到注册中收。

插件定义

public class NacosDiscoveryPropertiesPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "com.alibaba.cloud.nacos.NacosDiscoveryProperties";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.cloud.NacosDiscoveryPropertiesInterceptor";@Overrideprotected ClassMatch enhanceClass() {return NameMatch.byName(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getConstructorMatcher() {return ElementMatchers.any();}@Overridepublic String getConstructorInterceptor() {return INTERCEPTOR_CLASS;}}};}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[0];}
}

实例uuid拦截上报

public class NacosDiscoveryPropertiesInterceptor implements InstanceConstructorInterceptor {@Overridepublic void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {ServerInstance instance = ServerInstance.getInstance();NacosDiscoveryProperties properties = (NacosDiscoveryProperties) objInst;Map<String, String> metadata = properties.getMetadata();metadata.put(GrayConstant.INSTANCE_UUID, instance.getUuid());metadata.put(GrayConstant.APP_NAME,instance.getAppName());}
}

eureka client增强

原因同上

插件定义

public class InstanceInfoPluginDefine extends ClassInstanceMethodsEnhancePluginDefine {private static final String ENHANCE_CLASS = "com.netflix.appinfo.InstanceInfo";private static final String INTERCEPTOR_CLASS = "com.dbcat.gray.agent.cloud.InstanceInfoInterceptor";@Overrideprotected ClassMatch enhanceClass() {return NameMatch.byName(ENHANCE_CLASS);}@Overridepublic ConstructorInterceptPoint[] getConstructorsInterceptPoints() {return new ConstructorInterceptPoint[]{new ConstructorInterceptPoint() {@Overridepublic ElementMatcher<MethodDescription> getConstructorMatcher() {return ElementMatchers.any();}@Overridepublic String getConstructorInterceptor() {return INTERCEPTOR_CLASS;}}};}@Overridepublic InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {return new InstanceMethodsInterceptPoint[0];}
}

实例uuid拦截上报

public class InstanceInfoInterceptor implements InstanceConstructorInterceptor {@Overridepublic void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {ServerInstance instance = ServerInstance.getInstance();InstanceInfo instanceInfo = (InstanceInfo) objInst;Map<String, String> metadata = instanceInfo.getMetadata();metadata.put(GrayConstant.INSTANCE_UUID, instance.getUuid());metadata.put(APP_NAME,instance.getAppName());}
}

未完,待续…

给大家安利一款mysql监控软件: 安装方便,消耗低,可视化,傻瓜式操作,可以监控慢日志详情、cpu、内存、连接数、tps 等信息
体验演示
下载地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/497500.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java基础知识22 java的反射机制

一 java反射机制 1.1 概述 Java反射&#xff0c;程序在运行时&#xff0c;动态获取类信息&#xff08;类元数据&#xff09;&#xff0c;获取字段属性&#xff0c;动态创建对象和调用方法。Spring框架正是基于反射机制&#xff0c;通过我们的配置文件&#xff0c;在项目运行时…

[羊城杯 2024]Check in

下载附件&#xff0c;解压的时候发现注释&#xff1a;5unVpeVXGvjFah 解压得到的flag.txt文件内容如下&#xff1a; 注释5unVpeVXGvjFah放到随波逐流中一键解码发现base58解码得出一个正常点的字符串&#xff1a;Welcome2GZ&#xff0c;应该是某个key&#xff1f; 去hex解码&am…

C++Primer 控制流

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

RJ45网口模块设计

1、以太网概述及RJ45实物 2、常用网口信号介绍 3、RJ45网口布局布线要点分析 4、总结 1、变压器下面需要进行挖空处理&#xff0c;以免底下的铜引入干扰&#xff0c;&#xff08;将多边形挖空区域的所在层设置为Multi-Layer多层&#xff09; 2、为了更直观的看一个类中线的长…

Metagenome宏基因组,未识别的物种unclassified

1&#xff1a;"Bacteria|Proteobacteria|Betaproteobacteria|Neisseriales|Neisseriaceae|Kingella" 2&#xff1a;"Bacteria|Proteobacteria|Betaproteobacteria|Neisseriales|Neisseriaceae|unclassified" # 未识别到的/未注解到的…

深度学习笔记1:神经网络与模型训练过程

参考博客&#xff1a;PyTorch深度学习实战&#xff08;1&#xff09;——神经网络与模型训练过程详解_pytorch 实战-CSDN博客 人工神经网络 ANN&#xff1a;张量及数学运算的集合&#xff0c;排列方式近似于松散的人脑神经元排列 组成 1&#xff09;输入层 2&#xff09;隐…

【多模态】从零学习多模态——2024学习笔记总结

从零学习多模态——2024学习笔记总结 前言1. preliminary2. Transformer和NLP基础3. 多模态模型原理和架构学习4. 动手实验多模态模型第一步尝试Swift框架使用数据验证 5. 总结 前言 2024快结束啦&#xff0c;半年抽空学了学多模态还挺好玩的&#xff0c;学习和踩坑记录记一下&…

CAT3D: Create Anything in 3D with Multi-View Diffusion Models 论文解读

24年5月的论文&#xff0c;上一版就是ReconFusion 目录 一、概述 二、相关工作 1、2D先验 2、相机条件下的2D先验 3、多视角先验 4、视频先验 5、前馈方法 三、Method 1、多视角扩散模型 2、新视角生成 3、3D重建 一、概述 该论文提出一种CAT3D方法&#xff0c;实现…

Python中构建终端应用界面利器——Blessed模块

在现代开发中&#xff0c;命令行应用已经不再仅仅是一个简单的文本输入输出工具。随着需求的复杂化和用户体验的重视&#xff0c;终端界面也逐渐成为一个不可忽视的设计环节。 如果你曾经尝试过开发终端UI&#xff0c;可能对传统的 print() 或者 input() 函数感到不满足&#…

5.若依的角色权限控制

RBAC 基于角色的访问控制&#xff0c;通过角色来分配和管理用户的菜单权限。 修改课程管理的菜单到主类目下 新建角色并分配菜单 新建用户并分配角色 添加一个根菜单&#xff0c;父级为主类目

flutter插件开发-ios

flutter插件开发是一个重要的技能&#xff0c;拓展flutter与原生的通信&#xff0c;将一些公用的东西封装&#xff0c;给不同的项目使用。 阅读前置&#xff1a; flutter基本通道调用 objective-c基础语法 ios项目基础知识 目录 1、创建一个插件项目2、项目结构3、编写原生代码…

手机租赁平台开发全攻略打造高效便捷的租赁服务系统

内容概要 手机租赁平台开发&#xff0c;简单说就是让用户能轻松租赁各类手机的高效系统。这一平台不仅帮助那些想要临时使用高端手机的人们节省了不少资金&#xff0c;还为商家开辟了新的收入渠道。随着智能手机的普及&#xff0c;很多人并不需要长期拥有一部手机&#xff0c;…

【从零开始入门unity游戏开发之——C#篇34】C#匿名函数(delegate )和Lambda表达式

文章目录 一、匿名函数&#xff08;delegate &#xff09;1、什么是匿名函数&#xff1f;2、匿名函数的基本语法2.1 语法2.2 **没有参数的匿名函数&#xff1a;**2.3 **有参数的匿名函数&#xff1a;**2.4 **有返回值的匿名函数&#xff1a;** 3、匿名函数的使用示例3.1 作为参…

echarts没有map地图解决方案

在echarts4.9以后的版本中移除了map地图 使用命令npm install echarts --save它会下载最新版本 的echarts 所有我们要下载回echarts4.9版本中 如果已经下载了最新的可以卸载 // 卸载echarts运行&#xff1a; npm uninstall echarts然后再去下载4.9版本 // 安装4.9版本的ech…

WebP Vs. PNG:哪种图像格式适合您的网站?

图像对任何网站都至关重要,可以增强视觉吸引力和用户体验。但是,图像也会显着影响网站的加载时间,因此必须针对 Web 使用对其进行优化。一种方法是使用正确的图像格式。

【Git】—— 代码版本控制工具git的安装及基本使用

目录 一、Git的核心作用 二、安装Git 三、本地仓库命令 1、初始化 2、查看文件状态 3、将文件添加到暂存区 4、将文件提交到本地仓库 5、查看提交日志 6、将暂存区文件取消暂存 7、回溯到指定版本 四、忽略文件 一、Git的核心作用 远程备份&#xff1a;将代码备份到…

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、或者…

阿里云人工智能ACA(七)——计算机视觉基础

一、自然语言处理基本介绍 1. 自然语言处理的定义 1-1 自然语言 人类使用的在社会生活中自然形成的语言 1-2 自然语言处理 目标是让计算机能够理解、解析、生成和处理人类的自然语言 包含自然语言理解和自然语言生成两部分组成 2. 自然语言处理的发展趋势 3.自然语言处理…

细说STM32F407单片机通过IIC读写EEPROM 24C02

目录 一、操作说明 二、工程配置 1、时钟、DEBUG、GPIO、USART6、NVIC、Code Generator 2、 IIC2 &#xff08;1&#xff09;Master Features组&#xff0c;主设备参数 &#xff08;2&#xff09;Slave Features组&#xff0c;从设备参数 三、软件设计 1、KELED 2、E…

redis开发与运维-redis04-redis客户端Jedis与连接池及客户端异常模拟

文章目录 【README】【1】redis客户端通信协议【2】java客户端Jedis连接redis集群【2.1】Jedis基本用法【2.2】Jedis操作5种数据类型代码实践【2.3】Jedis使用序列化api操作【2.3.1】操作Jedis字节数组api代码实践 【3】Jedis连接池【3.1】Jedis连接池JedisPool代码实践【3.1.1…