Zipkin的官方介紹:https://zipkin.apache.org/前端
Zipkin是一款開源的分佈式實時數據追蹤系統(Distributed Tracking System),基於 Google Dapper的論文設計而來,由 Twitter 公司開發貢獻。其主要功能是彙集來自各個異構系統的實時監控數據。分佈式跟蹤系統還有其餘比較成熟的實現,例如:Naver的Pinpoint、Apache的HTrace、阿里的鷹眼Tracing、京東的Hydra、新浪的Watchman,美團點評的CAT,skywalking等。java
隨着業務愈來愈複雜,系統也隨之進行各類拆分,特別是隨着微服務架構和容器技術的興起,看似簡單的一個應用,後臺可能有幾十個甚至幾百個服務在支撐;一個前端的請求可能須要屢次的服務調用最後才能完成;當請求變慢或者不可用時,咱們沒法得知是哪一個後臺服務引發的,這時就須要解決如何快速定位服務故障點,Zipkin分佈式跟蹤系統就能很好的解決這樣的問題。git
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。用來在海量的請求中找到同一鏈路的幾回請求。好比servlet服務器接收到用戶請求,調用dubbo服務,而後將結果返回給用戶,整條鏈路只有一個traceId。開始於用戶請求,結束於用戶收到結果。sql
一個鏈路中每次請求都會有一個spanId。例如一次rpc,一次sql都會有一個單獨的spanId從屬於traceId。docker
Clent Sent 客戶端發起請求的時間,好比 dubbo 調用端開始執行遠程調用以前。apache
Client Receive 客戶端收處處理完請求的時間。api
Server Receive 服務端處理完邏輯的時間。
Server Receive 服務端收到調用端請求的時間。
sr - cs = 請求在網絡上的耗時 ss - sr = 服務端處理請求的耗時 cr - ss = 迴應在網絡上的耗時 cr - cs = 一次調用的總體耗時
當用戶發起一次調用時,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的 github 地址:https://github.com/apache/incubator-zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
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 服務器,以便在 UI 上渲染出來。
<!-- 使用 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>
zipkin: url: http://127.0.0.1:9411/api/v2/spans connectTimeout: 5000 readTimeout: 10000 # 取樣率,指的是屢次請求中有百分之多少傳到zipkin。例如 1.0 是所有取樣,0.5是 50% 取樣 rate: 1.0f
@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") 生效哦!
@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 的集成作好了:
踩過的坑以下,共勉:
若是仍然想查看,某個請求路徑的調用狀況呢?
github 源代碼:https://github.com/JMCuixy/dubbo-demo