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-servertrace-1trace-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-1trace-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.propertiesspring.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 IDSpan ID

  • Trace ID :为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的跟踪标识Trace ID,同时在分布式系统内部流转的时候,框架始终保持传递该唯一标识,直到返回给请求方为止。通过Trace ID的记录,我们就能将所有请求过程日志关联起来。在一次服务请求链路的调用过程中,会保持并传递同一个Trace ID,从而将整个分布于不同微服务进程中的请求跟踪信息串联起来,以上面输出内容为例,trace-1trace-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-1trace-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

 

posted on 2020-08-07 16:53  dreamstar  阅读(109)  评论(0编辑  收藏  举报