分佈式跟蹤系統zipkin簡介

1.概述

Zipkin是根據Google Dapper的論文設計的全鏈路監控系統,由Twitter公司開發。mysql

Zipkin 以 Trace 結構表示對一次請求的追蹤,又把每一個 Trace 拆分爲若干個有依賴關係的 Span。在微服務架構中,一次用戶請求可能會由後臺若干個服務負責處理,那麼每一個處理請求的服務就能夠理解爲一個 Span(能夠包括 API 服務,緩存服務,數據庫服務以及報表服務等)。固然這個服務也可能繼續請求其餘的服務,所以 Span 是一個樹形結構,以體現服務之間的調用關係。web

2.架構圖

zipkin架構圖

虛線爲zipkin-server提供的功能,主要包括四個模塊:spring

  • Collector 接受收集zipkin的客戶端傳輸的數據。
  • Storage 存儲收集來的數據,默認是Memory,可配置爲MySQL,Cassandra,ES等。
  • API 負責查詢Storage中存儲的數據,提供給UI使用。
  • UI 提供簡單的web頁面。

Instrumented爲採集數據並將數據發送給zipkin的客戶端。其主要採集的數據結構爲Trace和Span。sql

3.Brave

Brave是Java版的zipkin客戶端。數據庫

咱們通常不會手動編寫Trace相關的代碼,Brave提供可一些開箱即用的庫,幫助咱們追蹤一些特定的請求。好比dubbo,grpc,servlet,mysql,httpClient,kafka,springMVC等。api

/**
     *  客戶端具體怎麼收集數據的demo
     */
    public static void main(String[] args) throws Exception{
        // 1.構建客戶端發送工具
        Sender sender = OkHttpSender.create("http://127.0.0.1:9411/api/v2/spans");
        // 2.構建異步reporter
        AsyncReporter asyncReporter = AsyncReporter.builder(sender)
                .closeTimeout(500, TimeUnit.MILLISECONDS)
                .build(SpanBytesEncoder.JSON_V2);
        // 3.構建tracing上下文
        Tracing tracing = Tracing.newBuilder()
                .localServiceName("myService")
                .spanReporter(asyncReporter)
                .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY,"shuang"))
                .currentTraceContext(ThreadContextCurrentTraceContext.create())
                .build();
        // 4.使用tracer建立span並操做start()和finish()方法
        Tracer tracer = tracing.tracer();
        Span span = tracer.newTrace().name("total").start();

        Span action_1 = tracer.newChild(span.context()).name("action-1").start();
        try {
            Thread.sleep(500);
        }finally {
            action_1.finish();
        }

        Span action_2 = tracer.newChild(span.context()).name("action-2").start();
        try {
            Thread.sleep(500);
        }finally {
            action_2.finish();
        }

        try {
            Thread.sleep(2000);
        }finally {
            span.finish();
        }
    }
複製代碼

3.Tracing簡介

Tracing中依賴的幾個重要類緩存

  • Endpoint IP,端口,應用服務名等信息
  • Reporter 採集數據提報器
  • Sampler 採樣器,根據TraceId來判斷該Trace是否須要被採樣
  • CurrentTraceContext 將TraceContext綁定到ThreadLocal中,以便當前線程獲取
  • Propagation 是一個能夠向數據攜帶的對象carrier上注入和提取數據的接口

3.1Sampler

public abstract class Sampler {
    /**
     *  根據traceId是否須要採樣
     */
    public abstract boolean isSampled(long traceId);
}
複製代碼

其提供了幾個默認的採樣器實現。ALWAYS_SAMPLE,NERVER_SAMPLE和一個可定義採樣率的採樣器CountingSampler。bash

4.Span簡介

採集數據和發送數據的核心接口爲Span.start()和Span.finish()。數據結構

/**
   *  RealSpan依賴於Trace上下文,Recorder。
   */
  static RealSpan create(TraceContext context, Clock clock, Recorder recorder) {
    return new AutoValue_RealSpan(context, clock, recorder);
  }
  
  public Span start(long timestamp) {
    recorder().start(context(), timestamp);
    return this;
  }
  
  public void finish(long timestamp) {
    recorder().finish(context(), timestamp);
  }
  
  public void finish(TraceContext context, long finishTimestamp) {
    MutableSpan span = spanMap.remove(context);
    if(span == null || noop.get()) return;
    synchronized (span) {
        span.finsh(finishTimestamp);
        reporter.report(span.toSpan());
    }
  }
複製代碼

RealSpan調用start()和finish(),獲取和TraceContext綁定的Span信息,記錄開始時間和結束時間,並在結束時,調用reporter的report方法,上報給zipkin。架構

5.與springMVC整合

Brave利用springMVC提供的攔截器機制,在攔截先後分別調用前面的span相關代碼,即作到對一次請求的監控。

<!-- Brave提供的攔截器 -->
   <mvc:interceptors>
    <bean class="brave.spring.webmvc.TracingHandlerInterceptor" factory-method="create">
      <constructor-arg type="brave.http.HttpTracing" ref="httpTracing"/>
    </bean>
  </mvc:interceptors>
複製代碼

在preHandle() 和 afterCompletion() 中分別調用span.start()和span.finish()方法完成對zipkin服務端的上報。詳見相關代碼。

6.與Mysql整合

Mysql也在執行sql先後也提供了一個攔截接口。

/**
  * mysql-connector.jar中提供的攔截接口
  */
 public interface StatementInterceptorV2 extends Extension {
    void init(Connection var1, Properties var2) throws SQLException;

    ResultSetInternalMethods preProcess(String var1, Statement var2, Connection var3) throws SQLException;

    boolean executeTopLevelOnly();

    void destroy();

    ResultSetInternalMethods postProcess(String var1, Statement var2, ResultSetInternalMethods var3, Connection var4, int var5, boolean var6, boolean var7, SQLException var8) throws SQLException;
}
複製代碼

在preProcess()中執行span.start(), 在postProcess()中執行span.finish()。詳見相關代碼。

7.其餘中間件整合略。

8.總結

對zipkin的簡單介紹。良好的框架設計會給開發者帶來許多便利。(zipkin的客戶端大可能是基於攔截接口實現的。)

相關文章
相關標籤/搜索