Zipkin — 微服務鏈路跟蹤.

1、Zipkin 介紹

Zipkin 是什麼?

 Zipkin的官方介紹:https://zipkin.apache.org/前端

 Zipkin是一款開源的分佈式實時數據追蹤系統(Distributed Tracking System),基於 Google Dapper的論文設計而來,由 Twitter 公司開發貢獻。其主要功能是彙集來自各個異構系統的實時監控數據。分佈式跟蹤系統還有其餘比較成熟的實現,例如:Naver的Pinpoint、Apache的HTrace、阿里的鷹眼Tracing、京東的Hydra、新浪的Watchman,美團點評的CAT,skywalking等。java

爲何用 Zipkin?

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

Zipkin的一些基本概念?

Brave

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

以下圖是 Brave 的結構圖。Brave 利用 reporter 向 Zipkin的 Collector 發送 trace 信息。
web

Brave 主要是利用攔截器在請求前和請求後分別埋點。例如 Spingmvc 監控使用 Interceptors,Mysql 監控使用 statementInterceptors。同理 Dubbo 的監控是利用 com.alibaba.dubbo.rpc.Filter 來過濾生產者和消費者的請求。spring

traceId

一次請求全局只有一個traceId。用來在海量的請求中找到同一鏈路的幾回請求。好比servlet服務器接收到用戶請求,調用dubbo服務,而後將結果返回給用戶,整條鏈路只有一個traceId。開始於用戶請求,結束於用戶收到結果。sql

spanId

一個鏈路中每次請求都會有一個spanId。例如一次rpc,一次sql都會有一個單獨的spanId從屬於traceId。docker

cs

Clent Sent 客戶端發起請求的時間,好比 dubbo 調用端開始執行遠程調用以前。apache

cr

Client Receive 客戶端收處處理完請求的時間。api

ss

Server Receive 服務端處理完邏輯的時間。

sr

Server Receive 服務端收到調用端請求的時間。

sr - cs = 請求在網絡上的耗時
ss - sr = 服務端處理請求的耗時
cr - ss = 迴應在網絡上的耗時
cr - cs = 一次調用的總體耗時

Zipkin的工做過程

 當用戶發起一次調用時,Zipkin 的客戶端會在入口處爲整條調用鏈路生成一個全局惟一的 trace id,併爲這條鏈路中的每一次分佈式調用生成一個 span id。span 與 span 之間能夠有父子嵌套關係,表明分佈式調用中的上下游關係。span 和 span 之間能夠是兄弟關係,表明當前調用下的兩次子調用。一個 trace 由一組 span 組成,能夠當作是由 trace 爲根節點,span 爲若干個子節點的一棵樹。

 Zipkin 會將 trace 相關的信息在調用鏈路上傳遞,並在每一個調用邊界結束時異步的把當前調用的耗時信息上報給 Zipkin Server。Zipkin Server 在收到 trace 信息後,將其存儲起來。隨後 Zipkin 的 Web UI 會經過 API 訪問的方式從存儲中將 trace 信息提取出來分析並展現。

2、Zipkin的部署與運行

Zipkin的 github 地址:https://github.com/apache/incubator-zipkin

Docker 方式

docker run -d -p 9411:9411 openzipkin/zipkin

Jar 包方式(JDK8)

curl -sSL https://zipkin.apache.org/quickstart.sh | bash -s
java -jar zipkin.jar

注意:以上方式的 Zipkin 都是基於內存存儲,Zipkin 重啓後數據會丟失,建議測試環境使用。Zipkin 支持的存儲類型有 inMemory、MySql、Cassandra、以及 ElasticsSearch 幾種方式。正式環境推薦使用 Cassandra 和 ElasticSearch。

3、Zipkin 與 Dubbo 和 Springmvc 的集成

上面咱們搭建好了 Zipkin 服務器,如今的任務就是如何把咱們系統內產生的請求數據報送給 Zipkin 服務器,以便在 UI 上渲染出來。

1. pom.xml

<!-- 使用 okhttp3 做爲 reporter -->
        <dependency>
            <groupId>io.zipkin.reporter2</groupId>
            <artifactId>zipkin-sender-okhttp3</artifactId>
            <version>2.8.2</version>
        </dependency>
        <!--  brave 對 dubbo 的集成 -->
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
            <version>5.6.3</version>
        </dependency>
        <!--  brave 對 mvc 的集成 -->
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-spring-webmvc</artifactId>
            <version>5.6.3</version>
        </dependency>

2. application.yml

zipkin:
  url: http://127.0.0.1:9411/api/v2/spans
  connectTimeout: 5000
  readTimeout: 10000
  # 取樣率,指的是屢次請求中有百分之多少傳到zipkin。例如 1.0 是所有取樣,0.5是 50% 取樣
  rate: 1.0f

3. ZipkinProperties.java

@Configuration
@ConfigurationProperties("zipkin")
public class ZipkinProperties {


    @Value("${spring.application.name}")
    private String serviceName;
    private String url;
    private Long connectTimeout;
    private Long readTimeout;
    private Float rate;


    /*getter and setter*/
}

注意:記得在 SpringBoot 的啓動類上加上 @EnableConfigurationProperties 註解才能使 @ConfigurationProperties("zipkin") 生效哦!

4. ZipkinConfig.java

@Configuration
public class ZipkinConfig {

    @Autowired
    private ZipkinProperties zipkinProperties;

    /**
     * 爲了實現 dubbo rpc調用的攔截
     *
     * @return
     */
    @Bean
    public Tracing tracing() {
        Sender sender = OkHttpSender.create(zipkinProperties.getUrl());
        AsyncReporter reporter = AsyncReporter.builder(sender)
                .closeTimeout(zipkinProperties.getConnectTimeout(), TimeUnit.MILLISECONDS)
                .messageTimeout(zipkinProperties.getReadTimeout(), TimeUnit.MILLISECONDS)
                .build();
        Tracing tracing = Tracing.newBuilder()
                .localServiceName(zipkinProperties.getServiceName())
                .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "shiliew"))
                .sampler(Sampler.create(zipkinProperties.getRate()))
                .spanReporter(reporter)
                .build();
        return tracing;
    }


    /**
     * MVC Filter,爲了實現 SpringMvc 調用的攔截
     * @param tracing
     * @return
     */
    @Bean
    public Filter tracingFilter(Tracing tracing) {
        HttpTracing httpTracing = HttpTracing.create(tracing);
        httpTracing.toBuilder()
                .serverParser(new HttpServerParser() {
                    @Override
                    public <Req> String spanName(HttpAdapter<Req, ?> adapter, Req req) {
                        return adapter.path(req);
                    }
                })
                .clientParser(new HttpClientParser() {
                    @Override
                    public <Req> String spanName(HttpAdapter<Req, ?> adapter, Req req) {
                        return adapter.path(req);
                    }
                }).build();
        return TracingFilter.create(httpTracing);
    }
}

如此,咱們就把 Zipkin 和 Dubbo 以及 Springmvc 的集成作好了:

踩過的坑以下,共勉:

  • Zipkin Server 必定要在調用後纔會產生數據,不會先把服務的信息註冊上去。
  • MVC 的攔截,span 的名字是以請求方式命名的,以下:
  • 若是仍然想查看,某個請求路徑的調用狀況呢?

  • github 源代碼:https://github.com/JMCuixy/dubbo-demo

相關文章
相關標籤/搜索