做者:社區 徐靖峯 原文地址:http://www.spring4all.com/article/156java
在服務比較少的年代,一個系統的接口響應緩慢一般可以迅速被發現,但現在的微服務模塊,大多具備規模大,依賴關係複雜等特性,錯綜複雜的網狀結構使得咱們不容易定位到某一個執行緩慢的接口。分佈式的服務跟蹤組件就是爲了解決這一個問題。其次,它解決了另外一個難題,在沒有它以前,咱們客戶會一直詢問:大家的系統有監控嗎?大家的系統有監控嗎?大家的系統有監控嗎?如今,謝天謝地,他們終於不問了。是有點玩笑的成分,但能夠確定的一點是,實現全鏈路監控是保證系統健壯性的關鍵因子。mysql
介紹Spring Cloud Sleuth和Zipkin的文章在網上其實並很多,因此我打算就我目前的系統來探討一下,如何實現鏈路監控。全鏈路監控這個詞意味着只要是不一樣系統模塊之間的調用都應當被監控,這就包括了以下幾種經常使用的交互方式:git
1 Http協議,如RestTemplate,Feign,Okhttp3,HttpClient...github
2 Rpc遠程調用,如Motan,Dubbo,GRPC...web
3 分佈式Event,如RabbitMq,Kafka...spring
而咱們項目目前混合使用了Http協議,Motan Rpc協議,因此本篇文章會着墨於實現這兩塊的鏈路監控。sql
上面的項目結構是本次demo的核心結構,其中數據庫
添加依賴api
所有依賴app
核心依賴
<dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-server</artifactId> </dependency> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-autoconfigure-ui</artifactId> </dependency> <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin-storage-mysql</artifactId> <version>1.28.0</version> </dependency>
zipkin-autoconfigure-ui
提供了默認了UI頁面,zipkin-storage-mysql
選擇將鏈路調用信息存儲在mysql中,更多的選擇能夠有elasticsearch,cassandra。
zipkin-server/src/main/resources/application.yml
spring: application: name: zipkin-server datasource: url: jdbc:mysql://localhost:3306/zipkin username: root password: root driver-class-name: com.mysql.jdbc.Driver zipkin: storage: type: mysql server: port: 9411
建立啓動類
@SpringBootApplication @EnableZipkinServer public class ZipkinServerApp { @Bean public MySQLStorage mySQLStorage(DataSource datasource) { return MySQLStorage.builder().datasource(datasource).executor(Runnable::run).build(); } public static void main(String[] args) { SpringApplication.run(ZipkinServerApp.class, args); } }
當前版本在手動配置數據庫以後纔不會啓動報錯,可能與版本有關。mysql相關的腳本能夠在此處下載:mysql初始化腳本。
zipkin-server單獨啓動後,就能夠看到鏈路監控頁面了,此時因爲沒有收集到任何鏈路調用記錄,顯示以下:
編寫order和goods兩個服務,在order暴露一個http端口,在goods中使用RestTemplate遠程調用,以後查看在zipkin服務端查看調用信息。
首先添加依賴,讓普通的應用具有收集和發送報告的能力,這一切在spring cloud sleuth的幫助下都變得很簡單
添加依賴
核心依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
spring-cloud-starter-zipkin
依賴內部包含了兩個依賴,等於同時引入了spring-cloud-starter-sleuth
,spring-cloud-sleuth-zipkin
兩個依賴。名字特別像,注意區分。
以order爲例介紹配置文件
order/src/main/resources/application.yml
spring: application: name: order # 1 zipkin: base-url: http://localhost:9411 # 2 sleuth: enabled: true sampler: percentage: 1 # 3 server: port: 8060
<1> 指定項目名稱能夠方便的標記應用,在以後的監控頁面能夠看到這裏的配置名稱
<2> 指定zipkin的服務端,用於發送鏈路調用報告
<3> 採樣率,值爲[0,1]之間的任意實數,顧名思義,這裏表明100%採集報告。
編寫調用類
服務端order
@RestController @RequestMapping("/api") public class OrderController { Logger logger = LoggerFactory.getLogger(OrderController.class); @RequestMapping("/order/{id}") public MainOrder getOrder(@PathVariable("id") String id) { logger.info("order invoking ..."); //<1> return new MainOrder(id, new BigDecimal(200D), new Date()); } }
客戶端goods
public MainOrder test(){ ResponseEntity<MainOrder> mainOrderResponseEntity = restTemplate.getForEntity("http://localhost:8060/api/order/1144", MainOrder.class); MainOrder body = mainOrderResponseEntity.getBody(); return body; }
<1> 首先觀察這一行日誌在控制檯是如何輸出的
2017-11-08 09:54:00.633 INFO [order,d251f40af64361d2,e46132755dc395e1,true] 2780 --- [nio-8060-exec-1] m.c.sleuth.order.web.OrderController : order invoking ...
比沒有引入sleuth以前多了一些信息,其中order,d251f40af64361d2,e46132755dc395e1,true
分別表明了應用名稱,traceId,spanId,當前調用是否被採集,關於trace,span這些專業詞語,強烈建議去看看Dapper這篇論文,有不少中文翻譯版本,並非想象中的學術範,很是容易理解,不少鏈路監控文章中的截圖都來自於這篇論文,我在此就再也不贅述概念了。
緊接着,回到zipkin-server的監控頁面,查看變化
到這裏,Http監控就已經完成了,若是你的應用使用了其餘的Http工具,如okhttp3,也能夠去[opentracing,zipkin相關的文檔中尋找依賴。
雖然說spring cloud是大勢所趨,其推崇的http調用方式也是鏈路監控的主要對象,但不得不認可目前大多數的系統內部調用仍然是RPC的方式,至少咱們內部的系統是如此,因爲咱們內部採用的RPC框架是weibo開源的motan,這裏以此爲例,介紹RPC的鏈路監控。motan使用SPI機制,實現了對鏈路監控的支持,https://github.com/weibocom/motan/issues/304這條issue中能夠得知其加入了opentracing標準化追蹤。但目前只能經過本身添加組件的方式才能配合spring-cloud-sleuth使用,下面來看看實現步驟。
filter-opentracing
實現思路:引入SleuthTracingFilter,做爲全局的motan過濾器,給每一次motan的調用打上traceId和spanId,並編寫一個SleuthTracingContext,持有一個SleuthTracerFactory工廠,用於適配不一樣的Tracer實現。
具體的實現能夠參考文末的地址
order/src/main/resources/META-INF/services/com.weibo.api.motan.filter.Filter
com.weibo.api.motan.filter.sleuth.SleuthTracingFilter
添加一行過濾器的聲明,使得項目可以識別
配置SleuthTracingContext
@Bean SleuthTracingContext sleuthTracingContext(@Autowired(required = false) org.springframework.cloud.sleuth.Tracer tracer){ SleuthTracingContext context = new SleuthTracingContext(); context.setTracerFactory(new SleuthTracerFactory() { @Override public org.springframework.cloud.sleuth.Tracer getTracer() { return tracer; } }); return context; }
使用spring-cloud-sleuth的Tracer做爲motan調用的收集器
爲服務端和客戶端配置過濾器
basicServiceConfigBean.setFilter("sleuth-tracing"); basicRefererConfigBean.setFilter("sleuth-tracing");
編寫調用測試類
order做爲客戶端
@MotanReferer GoodsApi goodsApi; @RequestMapping("/goods") public String getGoodsList() { logger.info("getGoodsList invoking ..."); return goodsApi.getGoodsList(); }
goods做爲服務端
@MotanService public class GoodsApiImpl implements GoodsApi { Logger logger = LoggerFactory.getLogger(GoodsApiImpl.class); @Override public String getGoodsList() { logger.info("GoodsApi invoking ..."); return "success"; } }
查看調用關係
第一張圖中,使用前綴http和motan來區別調用的類型,第二張圖中,依賴變成了雙向的,由於一開始的http調用goods依賴於order,而新增了motan rpc調用以後order又依賴於goods。
系統間交互的方式除了http,rpc,還有另外的方式如mq,之後還可能會有更多的方式,但實現的監控的思路都是一致的,即如何無侵入式地給調用打上標籤,記錄報告。Dapper給實現鏈路監控提供了一個思路,而OpenTracing爲各個框架不一樣的調用方式提供了適配接口....Spring Cloud Sleuth則是遵循了Spring一向的風格,整合了豐富的資源,爲咱們的系統集成鏈路監控提供了很大的便捷性。
關於motan具體實現鏈路監控的代碼因爲篇幅限制,將源碼放在了個人github中,若是你的系統使用了motan,能夠用於參考:https://github.com/lexburner/sleuth-starter
《Spring Cloud微服務實戰》-- 翟永超
黃桂錢老師的指導