本文采用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来计算各个环节的时间延迟。