zoukankan      html  css  js  c++  java
  • dubbo + zipkin 实现全链路追踪

    随着业务的发展,应用的规模不断的扩大,传统的应用架构无法满足诉求,服务化架构改造势在必行,以 Dubbo 为代表的分布式服务框架成为了服务化改造架构中的基石。随着微服务理念逐渐被大众接受,应用进一步向更细粒度拆分,并且,不同的应用由不同的开发团队独立负责,整个分布式系统变得十分复杂。没有人能够清晰及时的知道当前系统整体的依赖关系。当出现问题时,也无法及时知道具体是链路上的哪个环节出了问题。

    本文介绍使用 dubbo zipkin 来实现全链路追踪,便于清晰的看出项目中各服务的调用关系以及各链路的信息。

    zipkin的介绍、安装请参考http://dubbo.apache.org/zh-cn/blog/use-zipkin-in-dubbo.html 这篇文章介绍了zipkin 以及dubbo与zipkin的集成。

    我主要来分享一下我在集成过程中遇到的问题:

    报错信息如下

    Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
    PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'filter' threw exception; nested exception is java.lang.IllegalStateException: No such extension tracing for filter/org.apache.dubbo.rpc.Filter
        at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:121)
        at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1566)
        ... 13 more

    这里主要是因为 我在注册dubbo服务时添加的filter没有找到所导致的错误

    经过分析:注册服务时添加的filter是从 com.alibaba.dubbo.rpc.Filter 文件中  tracing = brave.dubbo.rpc.TracingFilter 调用的TracingFilter 过滤器而不是我spring配置 文件中配置的bean。如下图

    我们配的filter=“tracing”实际调用的是下面文件中的过滤器

    下面我们看一下brave.dubbo.rpc.TracingFilter中的代码:

    package brave.dubbo.rpc;
    
    import brave.Span;
    import brave.Span.Kind;
    import brave.Tracer;
    import brave.Tracing;
    import brave.internal.Platform;
    import brave.propagation.Propagation;
    import brave.propagation.TraceContext;
    import brave.propagation.TraceContextOrSamplingFlags;
    import com.alibaba.dubbo.common.Constants;
    import com.alibaba.dubbo.common.extension.Activate;
    import com.alibaba.dubbo.common.extension.ExtensionLoader;
    import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
    import com.alibaba.dubbo.remoting.exchange.ResponseCallback;
    import com.alibaba.dubbo.rpc.Filter;
    import com.alibaba.dubbo.rpc.Invocation;
    import com.alibaba.dubbo.rpc.Invoker;
    import com.alibaba.dubbo.rpc.Result;
    import com.alibaba.dubbo.rpc.RpcContext;
    import com.alibaba.dubbo.rpc.RpcException;
    import com.alibaba.dubbo.rpc.protocol.dubbo.FutureAdapter;
    import com.alibaba.dubbo.rpc.support.RpcUtils;
    import java.net.InetSocketAddress;
    import java.util.Map;
    import java.util.concurrent.Future;
    
    @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}, value = "tracing")
    // http://dubbo.io/books/dubbo-dev-book-en/impls/filter.html
    // public constructor permitted to allow dubbo to instantiate this
    public final class TracingFilter implements Filter {
    
      Tracer tracer;
      TraceContext.Extractor<Map<String, String>> extractor;
      TraceContext.Injector<Map<String, String>> injector;
    
      /**
       * {@link ExtensionLoader} supplies the tracing implementation which must be named "tracing". For
       * example, if using the {@link SpringExtensionFactory}, only a bean named "tracing" will be
       * injected.
       */
      public void setTracing(Tracing tracing) {
        tracer = tracing.tracer();
        extractor = tracing.propagation().extractor(GETTER);
        injector = tracing.propagation().injector(SETTER);
      }
    
      @Override
      public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (tracer == null) return invoker.invoke(invocation);
    
        RpcContext rpcContext = RpcContext.getContext();
        Kind kind = rpcContext.isProviderSide() ? Kind.SERVER : Kind.CLIENT;
        final Span span;
        if (kind.equals(Kind.CLIENT)) {
          span = tracer.nextSpan();
          injector.inject(span.context(), invocation.getAttachments());
        } else {
          TraceContextOrSamplingFlags extracted = extractor.extract(invocation.getAttachments());
          span = extracted.context() != null
              ? tracer.joinSpan(extracted.context())
              : tracer.nextSpan(extracted);
        }
    
        if (!span.isNoop()) {
          span.kind(kind);
          String service = invoker.getInterface().getSimpleName();
          String method = RpcUtils.getMethodName(invocation);
          span.name(service + "/" + method);
          parseRemoteAddress(rpcContext, span);
          span.start();
        }
    
        boolean isOneway = false, deferFinish = false;
        try (Tracer.SpanInScope scope = tracer.withSpanInScope(span)) {
          Result result = invoker.invoke(invocation);
          if (result.hasException()) {
            onError(result.getException(), span);
          }
          isOneway = RpcUtils.isOneway(invoker.getUrl(), invocation);
          Future<Object> future = rpcContext.getFuture(); // the case on async client invocation
          if (future instanceof FutureAdapter) {
            deferFinish = true;
            ((FutureAdapter) future).getFuture().setCallback(new FinishSpanCallback(span));
          }
          return result;
        } catch (Error | RuntimeException e) {
          onError(e, span);
          throw e;
        } finally {
          if (isOneway) {
            span.flush();
          } else if (!deferFinish) {
            span.finish();
          }
        }
      }
    
      static void parseRemoteAddress(RpcContext rpcContext, Span span) {
        InetSocketAddress remoteAddress = rpcContext.getRemoteAddress();
        if (remoteAddress == null) return;
        span.remoteIpAndPort(Platform.get().getHostString(remoteAddress), remoteAddress.getPort());
      }
    
      static void onError(Throwable error, Span span) {
        span.error(error);
        if (error instanceof RpcException) {
          span.tag("dubbo.error_code", Integer.toString(((RpcException) error).getCode()));
        }
      }
    
      static final Propagation.Getter<Map<String, String>, String> GETTER =
          new Propagation.Getter<Map<String, String>, String>() {
            @Override
            public String get(Map<String, String> carrier, String key) {
              return carrier.get(key);
            }
    
            @Override
            public String toString() {
              return "Map::get";
            }
          };
    
      static final Propagation.Setter<Map<String, String>, String> SETTER =
          new Propagation.Setter<Map<String, String>, String>() {
            @Override
            public void put(Map<String, String> carrier, String key, String value) {
              carrier.put(key, value);
            }
    
            @Override
            public String toString() {
              return "Map::set";
            }
          };
    
      static final class FinishSpanCallback implements ResponseCallback {
        final Span span;
    
        FinishSpanCallback(Span span) {
          this.span = span;
        }
    
        @Override public void done(Object response) {
          span.finish();
        }
    
        @Override public void caught(Throwable exception) {
          onError(exception, span);
          span.finish();
        }
      }
    }
    我们可以发现类上面的这个注解 @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}, value = "tracing")
    注入的值是tracing 这时调用的才是我们在配置文件中的bean。

    形象图如下:

     导包历史如下:

     

    调整完事启动服务完美运行: 依赖关系展示成功

  • 相关阅读:
    JDBC原理
    练习 map集合被使用是因为具备映射关系 "进度班" "01" "张三" "进度班" "02" "李四" "J1701" "01" "王五" "J1701" "02" "王二" 此信息中,我们要怎样把上述信息装入集合中, 根据班级信息的到所有的所有信
    练习 HashSet 去重复
    集合练习 练习:每一个学生Student都有一个对应的归属地定义为String类型。学生属性:姓名,年龄 注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。 1、描述学生。 2、定义Map容器,将学生作为键,地址作为值存入集合中。 3、获取Map中的元素并进行排序。
    Java学习之Iterator(迭代器)的一般用法 (转)
    int 跟 Integer 的关系
    第十节 集合类Collection和Map
    类 Arrays StringBuilder 跟 StringBuffer 的异同 SimpleDateFormat
    数字转成字母型
    nginx之206异常
  • 原文地址:https://www.cnblogs.com/jack-yc/p/10408584.html
Copyright © 2011-2022 走看看