1. 程式人生 > >dubbo + zipkin 實現全鏈路追蹤

dubbo + zipkin 實現全鏈路追蹤

lte parser gflags 成功 bstr factory arr hup 分布式系

隨著業務的發展,應用的規模不斷的擴大,傳統的應用架構無法滿足訴求,服務化架構改造勢在必行,以 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。

形象圖如下:

技術分享圖片

導包歷史如下:

技術分享圖片

調整完事啟動服務完美運行: 依賴關系展示成功

技術分享圖片

dubbo + zipkin 實現全鏈路追蹤