Spring Cloud Sleuth 分布式服务跟踪
原文请参考Spring Cloud构建微服务架构:分布式服务跟踪(入门)【Dalston版】和 Spring Cloud构建微服务架构:分布式服务跟踪(跟踪原理)【Dalston版】我只是在学习过程中,记录一下,加深记忆和理解。
使用Spring Cloud Sleuth来为我们的微服务架构增加分布式服务跟踪的能力。
准备工作
1.服务注册中心eureka-server
2.创建微服务trace-1:实现一个REST接口/trace-1
,调用该接口后将通过Ribbon触发对trace-2
应用的调用。
- 创建基本的spring boot应用,添加依赖起步依赖spring-cloud-starter-netflix-eureka-server和spring-cloud-starter-netflix-ribbo
- 在配置类添加注解@EnableDiscoveryClient 把微服务注册到服务注册中心
- 配置application.properties文件 :配置微服务的名称和端口,指定注册中心的地址
#指定微服务名称 使用微服务名称就可以访问微服务
spring.application.name=trace-1
#指定微服务端口
server.port=9101
eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/
- 在配置类中初始化RestTemplate,用来真正发起REST请求。并增加@LoadBalanced注解
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
- 实现一个REST接口
/trace-1
,调用该接口后将通过Ribbon触发对trace-2
应用的调用
package com.example.trace1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class Trace1Controller {
@Autowired
private RestTemplate restTemplate;
Logger logger = LoggerFactory.getLogger(Trace1Controller.class);
@RequestMapping(value = "/trace-1", method = RequestMethod.GET)
public String trace() {
logger.info("===call trace-1===");
return restTemplate.getForEntity("http://trace-2/trace-2", String.class).getBody();
}
}
3.微服务trace-2 :实现一个REST接口/trace-2
,供trace-1
调用
- 创建基本的spring boot应用,添加依赖起步依赖spring-cloud-starter-netflix-eureka-server和spring-cloud-starter-netflix-ribbon
- 在配置类添加注解@EnableDiscoveryClient 把微服务注册到服务注册中心
- 配置application.properties文件 :配置微服务的名称和端口,指定注册中心的地址
#微服务的名称:后续在调用的时候只需要使用该名称就可以进行服务的访问
spring.application.name=trace-2
#微服务端口
server.port=9102
#指定服务注册中心的位置
eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/
- 实现一个REST接口
/trace-2 供trace-1微服务调用
package com.example.trace2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Trace2Controller {
Logger logger = LoggerFactory.getLogger(Trace2Controller.class);
@RequestMapping(value = "/trace-2", method = RequestMethod.GET)
public String trace() {
logger.info("===<call trace-2>===");
return "Trace";
}
}
4.将eureka-server
、trace-1
、trace-2
三个应用都启动起来,trace-1调用微服务trace-2,看log
通过postman或curl等工具来对trace-1
的接口发送请求http://localhost:9101/trace-1
,我们可以得到返回值Trace
在trace-1的控制台可以看到log如下
2020-08-05 10:59:14.715 INFO 13304 --- [nio-9101-exec-1] com.example.trace1.Trace1Controller : ===call trace-1===
在trace-2的控制台可以看到log如下
2020-08-05 10:59:14.992 INFO 20684 --- [nio-9102-exec-1] com.example.trace2.Trace2Controller : ===<call trace-2>===
到此都还没用到netflix sleuth的跟踪功能,只是看一下没有sleuth跟踪功能的微服务的日志是以上这样的。
5.为上面的trace-1
和trace-2
来添加服务跟踪功能
为应用添加服务跟踪能力, 只需要在pom.xml
依赖管理中增加spring-cloud-starter-sleuth
依赖即可
6.再次启动trace-1和trace2,然后发起请求qingqhttp://localhost:9101/trace-1
在trace-1的控制台可以看到log如下
2020-08-05 11:10:43.789 INFO [trace-1,cecade953d92daa9,cecade953d92daa9,true] 13452 --- [nio-9101-exec-1] com.example.trace1.Trace1Controller : ===call trace-1===
在trace-2的控制台可以看到log如下
2020-08-05 11:10:44.060 INFO [trace-2,cecade953d92daa9,e77155b746684779,true] 16956 --- [nio-9102-exec-1] com.example.trace2.Trace2Controller : ===<call trace-2>===
7.Spring Cloud Sleuth解释
从上面log中,我们可以看到多了一些形如[trace-1,cecade953d92daa9,cecade953d92daa9,true]
的日志信息,而这些元素正是实现分布式服务跟踪的重要组成部分,它们每个值的含义如下:
- 第一个值:
trace-1
,应用名称,也就是application.properties
中spring.application.name
参数配置的属性。 - 第二个值:
f410ab57afd5c145
,Spring Cloud Sleuth生成的一个ID,称为Trace ID,它用来标识一条请求链路。一条请求链路中包含一个Trace ID,多个Span ID。 - 第三个值:
a9f2118fa2019684
,Spring Cloud Sleuth生成的另外一个ID,称为Span ID,它表示一个基本的工作单元,比如:发送一个HTTP请求。 - 第四个值:
true
,表示是否要将该信息输出到Zipkin等服务中来收集和展示。
Spring Cloud Sleuth实现 分布式系统中的服务跟踪 有两个关键点 Trace ID
和Span ID
- Trace ID :为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的跟踪标识Trace ID,同时在分布式系统内部流转的时候,框架始终保持传递该唯一标识,直到返回给请求方为止。通过Trace ID的记录,我们就能将所有请求过程日志关联起来。在一次服务请求链路的调用过程中,会保持并传递同一个
Trace ID
,从而将整个分布于不同微服务进程中的请求跟踪信息串联起来,以上面输出内容为例,trace-1
和trace-2
同属于一个前端服务请求来源,所以他们的Trace ID
是相同的,处于同一条请求链路中。 - Span ID :为了统计各处理单元的时间延迟,当请求达到各个服务组件时,或是处理逻辑到达某个状态时,也通过一个唯一标识Span ID来标记它的开始、具体过程以及结束。对于每个Span来说,它必须有开始和结束两个节点,通过记录开始Span和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含一些其他元数据,比如:事件名称、请求信息等。
8.spring-cloud-starter-sleuth依赖
在项目中引入spring-cloud-starter-sleuth
依赖之后, 它会自动的为当前应用构建起各通信通道的跟踪机制,比如:
- 通过诸如RabbitMQ、Kafka(或者其他任何Spring Cloud Stream绑定器实现的消息中间件)传递的请求
- 通过Zuul代理传递的请求
- 通过
RestTemplate
发起的请求
trace-1
对trace-2
发起的请求是通过RestTemplate
实现的,所以spring-cloud-starter-sleuth
组件会对该请求进行处理,在发送到trace-2
之前sleuth会为在该请求的Header中增加实现跟踪需要的重要信息,主要有下面这几个:
- X-B3-TraceId:一条请求链路(Trace)的唯一标识,必须值
- X-B3-SpanId:一个工作单元(Span)的唯一标识,必须值
- X-B3-ParentSpanId::标识当前工作单元所属的上一个工作单元,Root Span(请求链路的第一个工作单元)的该值为空
- X-B3-Sampled:是否被抽样输出的标志,1表示需要被输出,0表示不需要被输出
- X-Span-Name:工作单元的名称
9.自定义要输出的跟踪信息
修改Trace2Controller如下
package com.example.trace2;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Trace2Controller {
Logger logger = LoggerFactory.getLogger(Trace2Controller.class);
@RequestMapping(value = "/trace-2", method = RequestMethod.GET)
public String trace(HttpServletRequest request) {
// logger.info("===<call trace-2>===");
logger.info("===<call trace-2, TraceId={}, SpanId={}>===", request.getHeader("X-B3-TraceId"),
request.getHeader("X-B3-SpanId"));
return "Trace";
}
}
再次发送请求http://localhost:9101/trace-1
,在trace-2的控制台可以看到log如下,多了一些跟踪信息的内容
2020-08-07 16:36:04.617 INFO [trace-2,6cc6f23b1789ccc4,a1c6088c16dfac6f,true] 25712 --- [nio-9102-exec-1] com.example.trace2.Trace2Controller : ===<call trace-2, TraceId=6cc6f23b1789ccc4, SpanId=a1c6088c16dfac6f>===
10.自定义要输出的跟踪信息 将Spring MVC的请求分发日志级别调整为DEBUG
级别
可以通过application.properties
中增加下面的配置,来将Spring MVC的请求分发日志级别调整为DEBUG
级别
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
再次发送请求http://localhost:9101/trace-1
,在trace-2的控制台可以看到log如下,多了一些跟踪信息的内容
2020-08-07 16:40:23.065 DEBUG [trace-2,c52101d193372b1d,d66e7ace3aaef4b9,true] 7796 --- [nio-9102-exec-1] o.s.web.servlet.DispatcherServlet : GET "/trace-2", parameters={}
2020-08-07 16:40:23.083 INFO [trace-2,c52101d193372b1d,d66e7ace3aaef4b9,true] 7796 --- [nio-9102-exec-1] com.example.trace2.Trace2Controller : ===<call trace-2, TraceId=c52101d193372b1d, SpanId=d66e7ace3aaef4b9>===
2020-08-07 16:40:23.098 DEBUG [trace-2,c52101d193372b1d,d66e7ace3aaef4b9,true] 7796 --- [nio-9102-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK