Zipkin—微服務鏈路跟蹤.

Apache GitHub MySQL Java Docker SQL Bash 設計 技術 Google Twitter Java的小本家 2019-06-02

一、Zipkin 介紹

Zipkin 是什麼?

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

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

為什麼用 Zipkin?

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

Zipkin的一些基本概念?

Brave

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

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

Zipkin—微服務鏈路跟蹤.

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

traceId

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

spanId

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

cs

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

cr

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

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 信息提取出來分析並展示。

Zipkin—微服務鏈路跟蹤.

回到頂部

二、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。

Zipkin—微服務鏈路跟蹤.

回到頂部

三、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—微服務鏈路跟蹤.

踩過的坑如下,共勉:

  • Zipkin Server 一定要在調用後才會產生數據,不會先把服務的信息註冊上去。
  • MVC 的攔截,span 的名字是以請求方式命名的,如下:
Zipkin—微服務鏈路跟蹤.


  • 如果仍然想查看,某個請求路徑的調用情況呢?
Zipkin—微服務鏈路跟蹤.

相關推薦

推薦中...