在当今的互联网应用中,分布式系统变得越来越普遍。一个大型的业务系统往往由多个微服务组成,这些微服务相互调用,共同完成复杂的业务逻辑。当系统出现问题时,由于服务之间的调用关系错综复杂,定位问题变得十分困难。分布式链路追踪工具应运而生,它可以帮助我们记录请求在各个服务之间的调用路径和相关信息,从而快速定位问题。Spring Cloud Sleuth 就是这样一款强大的分布式链路追踪工具,它为 Spring 生态系统提供了无缝的集成,能够方便地实现日志追踪。
Trace 代表一个完整的请求调用链,它是由一系列的 Span 组成。每个 Trace 都有一个唯一的 Trace ID,用于标识这个请求调用链。
Span 是 Trace 中的一个基本工作单元,它表示一次独立的调用。每个 Span 都有一个唯一的 Span ID,同时它还包含了一些元数据,如开始时间、结束时间、调用的服务名等。Span 之间可以有父子关系,形成一个树形结构。
Baggage 是一个键值对的集合,它可以在整个 Trace 中传递。Baggage 中的数据可以在不同的 Span 中被访问和修改,常用于传递一些全局的上下文信息。
我们创建两个 Spring Boot 项目,分别命名为 service-a
和 service-b
,并添加 Sleuth 依赖。
service-a
的 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
service-b
的 pom.xml
同样添加 spring-boot-starter-web
和 spring-cloud-starter-sleuth
依赖。
service-a
的控制器代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ServiceAController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call-service-b")
public String callServiceB() {
String response = restTemplate.getForObject("http://localhost:8081/service-b", String.class);
return "Service A called Service B. Response: " + response;
}
}
service-b
的控制器代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceBController {
@GetMapping("/service-b")
public String serviceB() {
return "Hello from Service B!";
}
}
在 application.properties
中添加以下配置:
spring.application.name=service-a # 对于 service-a 项目
# spring.application.name=service-b # 对于 service-b 项目
server.port=8080 # 对于 service-a 项目
# server.port=8081 # 对于 service-b 项目
分别启动 service-a
和 service-b
项目,然后访问 http://localhost:8080/call-service-b
,在控制台可以看到类似如下的日志:
[service-a,5d3a8a7c6a9d1b2e,5d3a8a7c6a9d1b2e,true] INFO ... - Handling call to /call-service-b
[service-b,5d3a8a7c6a9d1b2e,3f8a9b7c6d8e9f0a,true] INFO ... - Handling call to /service-b
日志中的方括号内的信息分别为:应用名、Trace ID、Span ID、是否采样。可以看到,两个服务的 Trace ID 是相同的,说明它们属于同一个请求调用链。
Sleuth 可以与日志框架(如 Logback、Log4j 等)集成,将 Trace ID 和 Span ID 输出到日志中。以 Logback 为例,在 logback-spring.xml
中添加以下配置:
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] [%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-B3-ParentSpanId:-},%X{X-Span-Export:-}] %-5level %logger{36} - %msg%n</pattern>
这样,日志中就会包含 Trace ID 和 Span ID 信息,方便我们进行追踪。
概念 | 描述 |
---|---|
Trace | 代表一个完整的请求调用链,有唯一的 Trace ID |
Span | 是 Trace 中的基本工作单元,有唯一的 Span ID,可形成树形结构 |
Baggage | 键值对集合,可在整个 Trace 中传递全局上下文信息 |
Spring Cloud Sleuth 是一款非常实用的分布式链路追踪工具,它可以帮助我们轻松地实现日志追踪,快速定位分布式系统中的问题。通过本文的演示,你可以看到 Sleuth 的使用非常简单,只需要添加依赖和少量的配置,就可以在项目中集成日志追踪功能。在实际开发中,我们可以结合其他工具(如 Zipkin)来实现更强大的分布式链路追踪功能。