在微服務盛行的時代,一個公司的應用數量動輒成百上千個。應用之間的依賴關係錯綜複雜,定位問題、排查問題是一件令人頭疼的事情。
爲了解決這個問題,Google的Dapper論文應運而生。Twitter基於該論文打造了自己的鏈路跟蹤系統(也就是本文章的主角):zipkin並將其開源
簡介
Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data.
Zipkin是一個分佈式追蹤系統。它有助於收集解決服務架構中的延遲問題所需的計時數據。功能包括收集和查找此數據。
簡單的介紹一下zipkin,詳細的介紹請移步:zipkin官網
架構
- reporter:上報鏈路數據的模塊,配置在具體的應用中
- transport:傳輸鏈路數據的模塊,通常爲http、Kafka
- collector:收集&消費鏈路數據的模塊,默認通過http收集,可以配置爲Kafka消費
- storage:存儲鏈路數據的模塊,具體實例可以爲ES、Cassandra或者mysql
鏈路數據模型
[
{
"traceId":"5982fe77008310cc80f1da5e10147517",
"name":"get",
"id":"bd7a977555f6b982",
"timestamp":1458702548467000,
"duration":386000,
"localEndpoint":{
"serviceName":"zipkin-query",
"ipv4":"192.168.1.2",
"port":9411
},
"annotations":[
{
"timestamp":1458702548467000,
"value":"sr"
},
{
"timestamp":1458702548853000,
"value":"ss"
}
]
}
]
其它更多有關於zipkin的信息請移步:
爲什麼要選zipkin
業界還有其它開源的鏈路跟蹤系統,爲什麼要選擇zipkin?
首先列舉自己的核心訴求:
- 性能影響小:能夠容忍輕微的性能損失
- 多語言支持:Java、Node、Go等
- 插件可擴展:可以定製化開發鏈路跟蹤插件
- 社區支持力度大:自己不需要過多的開發鏈路插件
- 接入成本小
業界開源的主流鏈路跟蹤系統:
- skywalking
- pinpoint
- zipkin
- jaeger
主要對比skywalking和zipkin
skywalking | zipkin | |
---|---|---|
內部實現方式 | javaagent,字節碼增強 | aop插件 |
語言支持 | 多語言 | 多語言 |
性能 | 好 | 好 |
插件擴展 | 困難 | 容易 |
接入成本 | 低,開發無感知 | 低,開發需要配置 |
社區支持 | 好 | 好 |
可以看到
- skywalking相較於zipkin的優勢在於接入成本低、性能稍好
- zipkin相較於skywalking的優勢在於插件擴展容易
我們最終選擇的是zipkin
zipkin和brave
首先說明一下zipkin和brave的關係:
- 從開頭的架構圖中可以看到:zipkin是服務端,用於查詢分析、收集和持久化鏈路數據
- brave則是zipkin官方出品的Java語言的鏈路數據採集插件。同理還有js、go版本的採集插件
搭建zipkin服務器
在官方的demo中提供了docker鏡像啓動和jar包啓動,但如果要做個性化開發的話必須通過自建項目然後引入zipkin server依賴進行啓動。
前面兩種啓動方式官網都有詳細的教程,這裏就不介紹了。下面主要介紹一下自建項目引入zipkin server依賴啓動的方式。
創建SpringBoot項目
創建好SpringBoot項目後,引入zipkin server相關jar包:
<!-- zipkin 核心依賴 -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>${zipkin-server.version}</version>
</dependency>
<!-- ui界面 可選 -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>${zipkin-server.version}</version>
</dependency>
<!-- es存儲 可選 -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-storage-elasticsearch</artifactId>
<version>${zipkin-server.version}</version>
</dependency>
<!-- kafka collector 可選 -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-collector-kafka</artifactId>
<version>${zipkin-server.version}</version>
</dependency>
配置kafka和es地址:
zipkin.collector.kafka.bootstrap-servers=
zipkin.collector.kafka.topic=
zipkin.collector.kafka.groupId=
zipkin.storage.type=elasticsearch
zipkin.storage.elasticsearch.hosts=
添加@EnableZipkinServer
註解
最後在SpringBoot啓動類上配置@EnableZipkinServer
註解
@EnableZipkinServer
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
至此,一個可運行的zipkin服務器就搭建完成了;定製化開發:報警、性能分析下篇博客再介紹。下面介紹一下brave的使用;
brave的使用
使用brave所需要的maven依賴附在文章末尾
官方提供的brave插件列表非常多,基本上涵蓋了日常用到的鏈路:http、rpc、db等。這是官方支持的中間件插件:
把Http API請求接入鏈路跟蹤
下面以將Http API接入鏈路跟蹤爲例,介紹需要配置的地方:官方demo
/**
* This adds tracing configuration to any web mvc controllers or rest template clients.
*/
@Configuration
// Importing a class is effectively the same as declaring bean methods
@Import(SpanCustomizingAsyncHandlerInterceptor.class)
public class TracingConfiguration extends WebMvcConfigurerAdapter {
/**
* Configuration for how to send spans to Zipkin
* 配置如何發送到zipkin服務器,這裏使用http的方式發送
*/
@Bean Sender sender() {
return OkHttpSender.create("http://127.0.0.1:9411/api/v2/spans");
}
/**
* Configuration for how to buffer spans into messages for Zipkin
* 配置reporter,何時發送到zipkin。觸發方式:定時、size大小等
* */
@Bean AsyncReporter<Span> spanReporter() {
return AsyncReporter.create(sender());
}
/**
* Controls aspects of tracing such as the service name that shows up in the UI
* 發送到zipkin的服務名,同一個應用的多個實例服務名應該相同
*/
@Bean Tracing tracing(@Value("${spring.application.name}") String serviceName) {
return Tracing.newBuilder()
.localServiceName(serviceName)
.propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "user-name"))
.currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder()
// puts trace IDs into logs
// 可以通過MDC.get("traceId")的方式拿到鏈路ID
.addScopeDecorator(MDCScopeDecorator.create())
.build()
)
.spanReporter(spanReporter()).build();
}
/**
* Allows someone to add tags to a span if a trace is in progress
* 允許添加自定義tag到鏈路中
* */
@Bean SpanCustomizer spanCustomizer(Tracing tracing) {
return CurrentSpanCustomizer.create(tracing);
}
/** Decides how to name and tag spans. By default they are named the same as the http method */
@Bean HttpTracing httpTracing(Tracing tracing) {
return HttpTracing.create(tracing);
}
/**
* Creates server spans for http requests
* 爲http請求自動創建鏈路或者span
* */
@Bean Filter tracingFilter(HttpTracing httpTracing) {
return TracingFilter.create(httpTracing);
}
/**
* 爲RestTemplate發起的請求自動創建zipkin的鏈路信息
* */
@Bean RestTemplateCustomizer useTracedHttpClient(HttpTracing httpTracing) {
final CloseableHttpClient httpClient = TracingHttpClientBuilder.create(httpTracing).build();
return new RestTemplateCustomizer() {
@Override public void customize(RestTemplate restTemplate) {
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
};
}
@Autowired SpanCustomizingAsyncHandlerInterceptor webMvcTracingCustomizer;
/** Decorates server spans with application-defined web tags */
@Override public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(webMvcTracingCustomizer);
}
}
上面的代碼的核心配置爲:
- sender:發送到zipkin服務器的方式:http或者kafka
- reporter:reporter決定何時將本地的鏈路數據發送到zipkin server
- tracing:非常重要,所有的鏈路跟蹤組件都依賴它。包括自己開發的鏈路跟蹤組件
- httpTracing、filter:爲http請求添加鏈路信息
把dubbo rpc請求接入鏈路跟蹤
因爲上一個步驟已經把brave核心的配置都已經陪好了,所以把dubbo鏈路加入到鏈路跟蹤就非常簡單了,兩個步驟:
首先引入brave dubbo相關依賴:
<!-- dubbo插件 -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-dubbo-rpc</artifactId>
</dependency>
然後再將brave dubbo filter添加到dubbo的filter鏈中:
- 方法1:在application.properties文件中添加兩行配置:
dubbo.consumer.filter=tracing
dubbo.provider.filter=tracing
- 方法2:在dubbo xml配置文件中添加配置
<dubbo:consumer filter="tracing"/>
<dubbo:provider filter="tracing"/>
對,就這麼簡單!
把mysql操作添加到鏈路跟蹤
數據庫操作這一環在整個請求鏈路中是非常重要的,很多問題都是因爲數據庫sql執行超時引起的。所以非常有必要把數據庫操作給監控起來,具體的配置參考官方就行:
/**
* A MySQL exception interceptor that will annotate spans with SQL error codes.
*
* <p>To use it, both TracingQueryInterceptor and TracingExceptionInterceptor must be added by
* appending <code>?queryInterceptors=brave.mysql8.TracingQueryInterceptor&exceptionInterceptors=brave.mysql8.TracingExceptionInterceptor</code>.
*/
其它的鏈路
其它的鏈路接入的方法類似,參考官方文檔即可,這裏就不展開介紹了。
其它
zipkin系列的文章
- 爲阿里雲ons/RocketMQ添加鏈路跟蹤
- zipkin server個性化開發:統計報表功能、報警服務
zipkin相關的網站
使用到的brave依賴
<!-- 核心依賴 -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave</artifactId>
</dependency>
<!-- reporter -->
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-okhttp3</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-kafka</artifactId>
</dependency>
<!-- 日誌依賴 -->
<!-- Integrates so you can use log patterns like %X{traceId}/%X{spanId} -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-context-slf4j</artifactId>
</dependency>
<!-- spring mvc項目支持 -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-spring-beans</artifactId>
</dependency>
<!-- mvc插件 -->
<!-- Adds the MVC class and method names to server spans -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-spring-webmvc</artifactId>
</dependency>
<!-- httpclient插件 -->
<!-- Instruments the underlying HttpClient requests that call the backend -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-httpclient</artifactId>
</dependency>
<!-- dubbo插件 -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-dubbo-rpc</artifactId>
</dependency>
<!-- mysql插件 -->
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-mysql8</artifactId>
</dependency>