本文采用Spring cloud本文爲2.1.8RELEASE,version=Greenwich.SR3
本文基於前兩篇文章eureka-server、eureka-client、eureka-ribbon和eureka-feign的實現。
參考java
現實生產環境當中,隨着業務的發展,系統規模是愈來愈大的,各個服務之間的調用也愈來愈複雜,一般一個由客戶端發起的請求在後端系統中會通過N個不一樣服務的來產生結果,這樣就會產生一個調用鏈路,每一條鏈路都有可能出現不通的錯誤或者是延遲,當出現錯誤或者延遲的狀況下,追蹤問題變的很是困難,因此Spring cloud爲咱們提供了Sleuth分佈式鏈路追蹤,能幫忙咱們快速定位問題以及相應的監控。(我這裏的demo模塊也好多,事後須要整理下,不影響小夥伴們的學習)web
在eureka-client、eureka-ribbon、eureka-feign工做中增長Sleuth依賴。spring
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>
在須要輸入日誌的地方增長日誌打印。這裏只簡單例舉eureka-ribbon工程中的controller日誌。json
package spring.cloud.demo.eurekaribbon.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import spring.cloud.demo.eurekaribbon.service.EurekaRibbonService; /** * @auther: maomao * @DateT: 2019-09-17 */ @RestController @Slf4j public class EurekaRibbonConntroller { @Autowired private EurekaRibbonService eurekaRibbonService; @RequestMapping("/sayHello") public String syaHello() { log.info("eureka-ribbon server......"); String message = eurekaRibbonService.sayHello(); log.info("[eureka-ribbon][EurekaRibbonConntroller][syaHello], message={}", message); return "ribbon result: " + message; } }
準備工做已經完成,這時候咱們按順序啓動全部服務。而後咱們訪問http://localhost:8901/sayHello,查看控制檯會輸出,bootstrap
2019-11-06 19:48:48.058 INFO [eureka-ribbon,086a3ab9cf8d31a8,086a3ab9cf8d31a8,false] 59750 --- [nio-8901-exec-9] s.c.d.e.c.EurekaRibbonConntroller : ribbon request, server=eureka-ribbon 調用 服務 eureka-client/info 服務 eureka-client/info 返回信息:http://eureka1.client.com:8801/info 調用 服務 eureka-client/info success 2019-11-06 19:48:48.351 INFO [eureka-ribbon,086a3ab9cf8d31a8,f06ab1e22c04430a,false] 59750 --- [ibbonService-10] s.c.d.e.service.EurekaRibbonService : ribbon->EurekaRibbonService->sayHello->調用 服務 eureka-client/info 返回信息:message=http://eureka1.client.com:8801/info 2019-11-06 19:48:48.351 INFO [eureka-ribbon,086a3ab9cf8d31a8,086a3ab9cf8d31a8,false] 59750 --- [nio-8901-exec-9] s.c.d.e.c.EurekaRibbonConntroller : ribbon request, server=eureka-ribbon, message=http://eureka1.client.com:8801/info
日誌說明:後端
咱們在控制檯中能夠查看到相似這樣的日誌:[eureka-ribbon,086a3ab9cf8d31a8,f06ab1e22c04430a,false],這些就是Sleuth幫忙咱們生成的。app
- 第一個值:eureka-ribbon,表明咱們的應用名稱。
- 第二個值:086a3ab9cf8d31a8,TraceID, 用來標識一條請求鏈路。
- 第三個值:f06ab1e22c04430a,SpanID,用來標識一個基本的工做單元。
- 第四個值:false,表示是否將該信息輸出到其餘日誌收集服務中,例如:Zipkin。
TraceID和SpanID關係:一個鏈路對應多個基本工做單元,也就是一個TraceID對應多個SpanID。分佈式
我這裏例舉的eureka-ribbon工程中的控制檯輸出的日誌內容,同理咱們能夠查看eureka-client工程的控制檯輸出,也會用相似的日誌輸出。
至此,Spring cloud Sleuth分佈式鏈路追蹤就初步搭建完成,由此咱們能夠總結出,Sleuth的核心就是生成的TraceID和SpanID,一條鏈路的日誌信息是由TraceID串聯起來的。
有了日誌輸出還不夠,咱們還須要日誌收集,官方文檔使用的是Logstash,接下來咱們開始整和Logstash。
<dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>6.2</version> </dependency>
這裏加入的是最新的logback依賴包,低版本的和Spring cloud 2.x版本不兼容。
在eureka-client和eureka-ribbon中加入logback-spring.xml,這裏須要注意的是,logback-spring.xml加載在application.yml配置以前,因此要新建bootstrap.yml,這樣logback-spring.xml才能獲取到對應的應用名稱。
bootstrap.yml設置:
spring: application: name: eureka-ribbon server: port: 8901
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <springProperty scope="context" name="springAppName" source="spring.application.name"/> <!-- Example for logging into the build folder of your project --> <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/> <!-- You can override this to have a custom pattern --> <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/> <!-- Appender to log to console --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <!-- Minimum logging level to be presented in the console logs--> <level>INFO</level> </filter> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>utf8</charset> </encoder> </appender> <!-- Appender to log to file in a JSON format --> <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}.json</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp> <timeZone>UTC</timeZone> </timestamp> <pattern> <pattern> { "severity": "%level", "service": "${springAppName:-}", "trace": "%X{X-B3-TraceId:-}", "span": "%X{X-B3-SpanId:-}", "parent": "%X{X-B3-ParentSpanId:-}", "exportable": "%X{X-Span-Export:-}", "pid": "${PID:-}", "thread": "%thread", "class": "%logger{40}", "rest": "%message" } </pattern> </pattern> </providers> </encoder> </appender> <root level="INFO"> <appender-ref ref="console"/> <!-- uncomment this to have also JSON logs --> <appender-ref ref="logstash"/> <!--<appender-ref ref="flatfile"/>--> </root> </configuration>
從新啓動相關服務,並訪問http://localhost:8901/sayHello,在相應的控制檯中能夠看到相似日誌,
2019-11-07 11:14:21.136 INFO [eureka-ribbon,0983491b6471be0f,48598b8942c2c814,false] 3288 --- [RibbonService-1] s.c.d.e.service.EurekaRibbonService : ribbon->EurekaRibbonService->sayHello->調用 服務 eureka-client/info 返回信息:message=http://eureka1.client.com:8801/info 2019-11-07 11:14:21.139 INFO [eureka-ribbon,0983491b6471be0f,0983491b6471be0f,false] 3288 --- [nio-8901-exec-1] s.c.d.e.c.EurekaRibbonConntroller : >>>traceId=null, spanId=null 2019-11-07 11:14:21.140 INFO [eureka-ribbon,0983491b6471be0f,0983491b6471be0f,false] 3288 --- [nio-8901-exec-1] s.c.d.e.c.EurekaRibbonConntroller : [eureka-ribbon][EurekaRibbonConntroller][syaHello], message=http://eureka1.client.com:8801/info, traceId=0983491b6471be0f
日誌內容以前已經進行過詳細的說明,這裏就不在說明,這時咱們能夠在工程目錄外發現有一個build的目錄,咱們進入這個build目錄能夠看到已應用名稱開頭的.json文件,該文件就是logback-spring.xml中配置的logstash的appender輸出的日誌文件。
logstash的日誌配置咱們就完成了,logstash除了能夠經過上面的方式生成json日誌文件以外,還可使用LogstashTcpSocketAppender將日誌內容直接輸出到logstash的服務端,這裏就不過多說明,感興趣的小夥伴能夠自行研究。
在Spring cloud D版本之後,zipkin-server是經過引入依賴的方式構建的,到了E版本以後,官方就是開始啓用了jar的形式來運行zipkin-server。因此咱們先到zipkin的官網下載最新的zipkin.jar。
在eureka-client、eureka-ribbon、spring-gateway增長相關依賴。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
在eureka-client、eureka-ribbon、spring-gateway應用的application.yml增長一下配置:
spring: sleuth: sampler: probability: 1 #採樣頻率 web: enabled: true zipkin: base-url: http://localhost:9411/ #zipkin服務地址
啓動eureka-client、eureka-ribbon、spring-gateway應用服務。
zipkin啓動方式:java -jar zipkin.jar
運行zipkin.jar之後,我訪問http://localhost:9411/zipkin,這時候咱們能夠看到以下圖顯示:
而後咱們在訪問http://localhost:8100/ribbon/sayHello?token=xxx地址(這個地址的請求鏈路是spring-gateway:eureka-ribbion:eureka-client),而後咱們點擊zipkin的查詢按鈕,咱們能夠看到以下顯示:
而後能夠點擊單個鏈路信息查看詳細信息,以下圖顯示:
由這張圖就可查看到詳細鏈路追蹤信息。
至此,整合zipkin就完成了,這種默認的方式是http收集,咱們還能夠採用消息中間件來收集日誌信息,感興趣的小夥伴能夠自行研究。
本文重點講述了Spring Cloud經過Sleuth+Zipkin實現了服務的跟蹤,後續我會補充一篇結合ELK的日誌收集。經過這篇文章咱們也簡單的瞭解了鏈路追蹤的原理,就是經過traceId將整個過程串聯起來,而後經過spanID來計算各個環節的時間延遲。