Zipkin快速開始

Zipkin是什麼
Zipkin分佈式跟蹤系統;它能夠幫助收集時間數據,解決在microservice架構下的延遲問題;它管理這些數據的收集和查找;Zipkin的設計是基於谷歌的Google Dapper論文。
每一個應用程序向Zipkin報告定時數據,Zipkin UI呈現了一個依賴圖表來展現多少跟蹤請求通過了每一個應用程序;若是想解決延遲問題,能夠過濾或者排序全部的跟蹤請求,而且能夠查看每一個跟蹤請求佔總跟蹤時間的百分比。html

爲何使用Zipkin
隨着業務愈來愈複雜,系統也隨之進行各類拆分,特別是隨着微服務架構和容器技術的興起,看似簡單的一個應用,後臺可能有幾十個甚至幾百個服務在支撐;一個前端的請求可能須要屢次的服務調用最後才能完成;當請求變慢或者不可用時,咱們沒法得知是哪一個後臺服務引發的,這時就須要解決如何快速定位服務故障點,Zipkin分佈式跟蹤系統就能很好的解決這樣的問題。前端

Zipkin下載和啓動
官方提供了三種方式來啓動,這裏使用第二種方式來啓動;java

wget -O zipkin.jar 'https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec'
java -jar zipkin.jar

首先下載zipkin.jar,而後直接使用-jar命令運行,要求jdk8以上版本;git

[root@localhost ~]# java -jar zipkin.jar 
                                    ********
                                  **        **
                                 *            *
                                **            **
                                **            **
                                 **          **
                                  **        **
                                    ********
                                      ****
                                      ****
        ****                          ****
     ******                           ****                                 ***
  ****************************************************************************
    *******                           ****                                 ***
        ****                          ****
                                       **
                                       **
 
 
             *****      **     *****     ** **       **     **   **
               **       **     **  *     ***         **     **** **
              **        **     *****     ****        **     **  ***
             ******     **     **        **  **      **     **   **
 
:: Powered by Spring Boot ::         (v1.5.8.RELEASE)
......
on || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
2017-12-06 22:09:17.498  INFO 7555 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-12-06 22:09:17.505  INFO 7555 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2017-12-06 22:09:17.789  INFO 7555 --- [           main] b.c.e.u.UndertowEmbeddedServletContainer : Undertow started on port(s) 9411 (http)
2017-12-06 22:09:17.794  INFO 7555 --- [           main] zipkin.server.ZipkinServer               : Started ZipkinServer in 16.867 seconds (JVM running for 19.199)

基於Undertow WEB服務器,提供對外端口:9411,能夠打開瀏覽器訪問http://ip:9411
圖片描述github

詳細參考:https://zipkin.io/pages/quick...web

Zipkin架構
跟蹤器(Tracer)位於你的應用程序中,並記錄發生的操做的時間和元數據,提供了相應的類庫,對用戶的使用來講是透明的,收集的跟蹤數據稱爲Span;
將數據發送到Zipkin的儀器化應用程序中的組件稱爲Reporter,Reporter經過幾種傳輸方式之一將追蹤數據發送到Zipkin收集器(collector),
而後將跟蹤數據進行存儲(storage),由API查詢存儲以向UI提供數據。
架構圖以下:
圖片描述spring

1.Trace
Zipkin使用Trace結構表示對一次請求的跟蹤,一次請求可能由後臺的若干服務負責處理,每一個服務的處理是一個Span,Span之間有依賴關係,Trace就是樹結構的Span集合;apache

2.Span
每一個服務的處理跟蹤是一個Span,能夠理解爲一個基本的工做單元,包含了一些描述信息:id,parentId,name,timestamp,duration,annotations等,例如:json

{
      "traceId": "bd7a977555f6b982",
      "name": "get-traces",
      "id": "ebf33e1a81dc6f71",
      "parentId": "bd7a977555f6b982",
      "timestamp": 1458702548478000,
      "duration": 354374,
      "annotations": [
        {
          "endpoint": {
            "serviceName": "zipkin-query",
            "ipv4": "192.168.1.2",
            "port": 9411
          },
          "timestamp": 1458702548786000,
          "value": "cs"
        }
      ],
      "binaryAnnotations": [
        {
          "key": "lc",
          "value": "JDBCSpanStore",
          "endpoint": {
            "serviceName": "zipkin-query",
            "ipv4": "192.168.1.2",
            "port": 9411
          }
        }
      ]
}

traceId:標記一次請求的跟蹤,相關的Spans都有相同的traceId;
id:span id;
name:span的名稱,通常是接口方法的名稱;
parentId:可選的id,當前Span的父Span id,經過parentId來保證Span之間的依賴關係,若是沒有parentId,表示當前Span爲根Span;
timestamp:Span建立時的時間戳,使用的單位是微秒(而不是毫秒),全部時間戳都有錯誤,包括主機之間的時鐘誤差以及時間服務從新設置時鐘的可能性,
出於這個緣由,Span應儘量記錄其duration;
duration:持續時間使用的單位是微秒(而不是毫秒);
annotations:註釋用於及時記錄事件;有一組核心註釋用於定義RPC請求的開始和結束;瀏覽器

cs:Client Send,客戶端發起請求;
sr:Server Receive,服務器接受請求,開始處理;
ss:Server Send,服務器完成處理,給客戶端應答;
cr:Client Receive,客戶端接受應答從服務器;

binaryAnnotations:二進制註釋,旨在提供有關RPC的額外信息。

3.Transport
收集的Spans必須從被追蹤的服務運輸到Zipkin collector,有三個主要的傳輸方式:HTTP, Kafka和Scribe;

4.Components
有4個組件組成Zipkin:collector,storage,search,web UI
collector:一旦跟蹤數據到達Zipkin collector守護進程,它將被驗證,存儲和索引,以供Zipkin收集器查找;
storage:Zipkin最初數據存儲在Cassandra上,由於Cassandra是可擴展的,具備靈活的模式,並在Twitter中大量使用;可是這個組件可插入,除了Cassandra以外,還支持ElasticSearch和MySQL;
search:一旦數據被存儲和索引,咱們須要一種方法來提取它。查詢守護進程提供了一個簡單的JSON API來查找和檢索跟蹤,主要給Web UI使用;
web UI:建立了一個GUI,爲查看痕跡提供了一個很好的界面;Web UI提供了一種基於服務,時間和註釋查看跟蹤的方法。

實戰
使用Zipkin和Brave實現http服務調用的跟蹤,Brave 是用來裝備Java程序的類庫,提供了面向標準Servlet、Spring MVC、Http Client、JAX RS、Jersey、Resteasy 和 MySQL 等接口的裝備能力,能夠經過編寫簡單的配置和代碼,讓基於這些框架構建的應用能夠向 Zipkin 報告數據。同時 Brave 也提供了很是簡單且標準化的接口,在以上封裝沒法知足要求的時候能夠方便擴展與定製。

提供四個工程,分別對應四個服務分別是:zipkin1,zipkin2,zipkin3,zipkin4;zipkin1經過httpclient調用zipkin2,而後zipkin2經過httpclient調用zipkin3和zipkin4,造成一個調用鏈;四個服務都是基於spring-boot來實現,對應的端口分別是8081,8082,8083,8084;

1.公共maven依賴庫

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-core</artifactId>
        <version>3.9.0</version>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-spancollector-http</artifactId>
        <version>3.9.0</version>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-web-servlet-filter</artifactId>
        <version>3.9.0</version>
    </dependency>
    <dependency>
        <groupId>io.zipkin.brave</groupId>
        <artifactId>brave-apache-http-interceptors</artifactId>
        <version>3.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>
</dependencies>

2.核心類ZipkinBean提供須要使用的Bean

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.Brave.Builder;
import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
import com.github.kristofa.brave.Sampler;
import com.github.kristofa.brave.SpanCollector;
import com.github.kristofa.brave.http.DefaultSpanNameProvider;
import com.github.kristofa.brave.http.HttpSpanCollector;
import com.github.kristofa.brave.http.HttpSpanCollector.Config;
import com.github.kristofa.brave.httpclient.BraveHttpRequestInterceptor;
import com.github.kristofa.brave.httpclient.BraveHttpResponseInterceptor;
import com.github.kristofa.brave.servlet.BraveServletFilter;
 
@Configuration
public class ZipkinBean {
 
    /**
     * 配置收集器
     * 
     * @return
     */
    @Bean
    public SpanCollector spanCollector() {
        Config config = HttpSpanCollector.Config.builder().compressionEnabled(false).connectTimeout(5000)
                .flushInterval(1).readTimeout(6000).build();
        return HttpSpanCollector.create("http://192.168.237.128:9411", config, new EmptySpanCollectorMetricsHandler());
    }
 
    /**
     * Brave各工具類的封裝
     * 
     * @param spanCollector
     * @return
     */
    @Bean
    public Brave brave(SpanCollector spanCollector) {
        Builder builder = new Builder("service1");// 指定serviceName
        builder.spanCollector(spanCollector);
        builder.traceSampler(Sampler.create(1));// 採集率
        return builder.build();
    }
 
    /**
     * 攔截器,須要serverRequestInterceptor,serverResponseInterceptor 分別完成sr和ss操做
     * 
     * @param brave
     * @return
     */
    @Bean
    public BraveServletFilter braveServletFilter(Brave brave) {
        return new BraveServletFilter(brave.serverRequestInterceptor(), brave.serverResponseInterceptor(),
                new DefaultSpanNameProvider());
    }
 
    /**
     * httpClient客戶端,須要clientRequestInterceptor,clientResponseInterceptor分別完成cs和cr操做
     * 
     * @param brave
     * @return
     */
    @Bean
    public CloseableHttpClient httpClient(Brave brave) {
        CloseableHttpClient httpclient = HttpClients.custom()
                .addInterceptorFirst(new BraveHttpRequestInterceptor(brave.clientRequestInterceptor(),
                        new DefaultSpanNameProvider()))
                .addInterceptorFirst(new BraveHttpResponseInterceptor(brave.clientResponseInterceptor())).build();
        return httpclient;
    }
}

3.核心類ZipkinController對外接口

@RestController
public class ZipkinController {
 
    @Autowired
    private CloseableHttpClient httpClient;
 
    @GetMapping("/service1")
    public String service() throws Exception {
        Thread.sleep(100);
        HttpGet get = new HttpGet("http://localhost:8082/service2");
        CloseableHttpResponse response = httpClient.execute(get);
        return EntityUtils.toString(response.getEntity(), "utf-8");
    }
}

分別啓動四個服務,而後瀏覽器訪問:http://localhost:8081/service1,正常調用結果返回:

service3 service4

能夠觀察zipkin web ui,查看服務的調用鏈:
圖片描述

相關文章
相關標籤/搜索