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

文章目录

前言

上一篇介绍,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";
      @Override
      protected ClassMatch enhanceClass() {
          return HierarchyMatch.byHierarchyMatch("org.springframework.web.servlet.HandlerAdapter");
      }
      @Override
      public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
          return new ConstructorInterceptPoint[0];
      }
      @Override
      public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
          return new InstanceMethodsInterceptPoint[] {
                  new InstanceMethodsInterceptPoint() {
                      @Override
                      public ElementMatcher<MethodDescription> getMethodsMatcher() {
                          return named("handle").and(takesArguments(3));
                      }
                      @Override
                      public String getMethodsInterceptor() {
                          return CLASS_INTERCEPTOR;
                      }
                      @Override
                      public boolean isOverrideArgs() {
                          return false;
                      }
                  }
          };
      }
  
      @Override
      public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
          return new StaticMethodsInterceptPoint[0];
      }
  }

2.实现灰度增强拦截

public class HandlerAdapterInterceptor implements InInterceptor, InstanceMethodsAroundInterceptor {
  @Override
  public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result){
      String routingEnv = getRoutingEnv(allArguments);
      this.setContext(routingEnv);
      CounterManager.increaseConsume(ComponentType.MVC,routingEnv);
  }
  @Override
  public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) {
      //清除threadLocal里的数据
      this.removeContext();
      return ret;
  }
  private String getRoutingEnv(Object[] allArguments){
      //从http 请求头或Attribute 获取灰度标签设置到threadLocal
      Object 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";
    @Override
    protected ClassMatch enhanceClass() {
        return new ThreadingMatch(CALLABLE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[] {
            new ConstructorInterceptPoint() {
                @Override
                public ElementMatcher<MethodDescription> getConstructorMatcher() {
                    //拦截构造,切换线程前保存灰度标签到当前Callable实现上
                    return any();
                }
                @Override
                public String getConstructorInterceptor() {
                    return CALLABLE_CLASS_INTERCEPTOR;
                }
            }
        };
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[] {
            new InstanceMethodsInterceptPoint() {
                @Override
                public ElementMatcher<MethodDescription> getMethodsMatcher() {
                    //拦截call方法
                    return named("call").and(takesArguments(0));
                }

                @Override
                public String getMethodsInterceptor() {
                    return CALLABLE_CALL_METHOD_INTERCEPTOR;
                }

                @Override
                public 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";
    @Override
    protected ClassMatch enhanceClass() {
        return new ThreadingMatch(RUNNABLE_CLASS);
    }
    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[] {
            new ConstructorInterceptPoint() {
                @Override
                public ElementMatcher<MethodDescription> getConstructorMatcher() {
                   //拦截构造,切换线程前保存灰度标签到当前Runnable实现上
                    return any();
                }
                @Override
                public String getConstructorInterceptor() {
                    return RUNNABLE_CLASS_INTERCEPTOR;
                }
            }
        };
    }
    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[] {
            new InstanceMethodsInterceptPoint() {
                @Override
                public ElementMatcher<MethodDescription> getMethodsMatcher() {
                    //拦载run方法
                    return named("run").and(takesArguments(0));
                }
                @Override
                public String getMethodsInterceptor() {
                    return RUNNABLE_RUN_METHOD_INTERCEPTOR;
                }

                @Override
                public boolean isOverrideArgs() {
                    return false;
                }
            }
        };
    }
}

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

public class ThreadingConstructorInterceptor implements InInterceptor, InstanceConstructorInterceptor {
    
    @Override
    public 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 {

    @Override
    public 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);
    }

    @Override
    public 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";

    @Override
    public boolean isBootstrapInstrumentation() {
        return true;
    }

    @Override
    protected ClassMatch enhanceClass() {
        return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS), MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS));
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("execute");
                    }
                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPT_EXECUTE_METHOD_HANDLE;
                    }
                    @Override
                    public boolean isOverrideArgs() {
                        return true;
                    }
                },
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("submit");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPT_SUBMIT_METHOD_HANDLE;
                    }
                    @Override
                    public boolean isOverrideArgs() {
                        return true;
                    }
                }
        };
    }
}

ThreadPool公共拦截类

public abstract class AbstractThreadPoolInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public 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);

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
        return ret;
    }

    @Override
    public 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 {

    @Override
    public 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 {

    @Override
    public 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";
    @Override
    protected ClassMatch enhanceClass() {
        return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {

                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("apply");
                    }
                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
}

Feign灰度标签拦截器

public class FeignContextInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {

                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("intercept");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
}

RestTemplate http 拦截灰度标签续传

public class HttpRequestContextInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {

                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("choose");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
}

Rule 灰度路由规则拦截改写

public class RuleInterceptor implements InstanceMethodsAroundInterceptor {
    @Override
    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("invoke");
                    }

                    @Override
                    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("invoke");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
}

服务消费方ContextFilter拦截

public class ConsumerContextInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public 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 {

    @Override
    public 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";
    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }
    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return ElementMatchers.named("route");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
}

灰度路由规则拦截改写

public class AppGrayRouterInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }


    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[]{
                new ConstructorInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getConstructorMatcher() {
                        return ElementMatchers.any();
                    }

                    @Override
                    public String getConstructorInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[0];
    }
}

实例uuid拦截上报

public class NacosDiscoveryPropertiesInterceptor implements InstanceConstructorInterceptor {
    
    @Override
    public 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";

    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }


    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[]{
                new ConstructorInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getConstructorMatcher() {
                        return ElementMatchers.any();
                    }

                    @Override
                    public String getConstructorInterceptor() {
                        return INTERCEPTOR_CLASS;
                    }
                }
        };
    }
    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[0];
    }
}

实例uuid拦截上报

public class InstanceInfoInterceptor implements InstanceConstructorInterceptor {
    
    @Override
    public 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 等信息
体验演示
下载地址

相关推荐
Dusk_橙子3 小时前
在K8S中,节点状态notReady如何排查?
云原生·容器·kubernetes
像污秽一样3 小时前
Eureka使用总结(自用)
云原生·eureka
m0_548049703 小时前
【MySQL — 数据库基础】深入理解数据库服务与数据库关系、MySQL连接创建、客户端工具及架构解析
数据库·mysql·架构
文火冰糖的硅基工坊3 小时前
[创业之路-230]:《华为闭环战略管理》-5-华为的组织架构与业务架构是不同的,组织架构是为业务架构服务
华为·架构·产品经理·管理·创业·战略
骑着王八撵玉兔3 小时前
【容器化技术 Docker 与微服务部署】详解
分布式·docker·微服务·中间件·容器·架构
骑着王八撵玉兔4 小时前
【Kafka 消息队列深度解析与应用】
分布式·spring·中间件·架构·kafka·rabbitmq·linq
AI人H哥会Java5 小时前
【Spring】Spring DI(依赖注入)详解—集合类型的注入——List、Set、Map的配置与注入
java·开发语言·后端·spring·架构
测试者家园8 小时前
SkyWalking概述
自动化测试·软件测试·微服务·性能测试·skywalking·性能监控·质量效能