如何使用Spring Cloud Sleuth进行分布式追踪

代码魔法师 2020-07-10 ⋅ 17 阅读

在微服务架构中,一个请求可能会经过多个微服务的处理,这就意味着当我们要对系统进行性能分析或故障排查时,需要追踪一个请求在不同服务间的传递。Spring Cloud Sleuth是Spring Cloud提供的分布式追踪解决方案,它通过在服务间传递唯一的追踪ID,可以清晰地追踪请求流程和定位潜在的性能问题。

引入依赖

首先,我们需要在项目的pom.xml文件中引入spring-cloud-starter-sleuth依赖,以使用Spring Cloud Sleuth:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

配置

接下来,我们需要对服务的配置文件进行一些调整,以开启和配置Spring Cloud Sleuth。

添加配置项

在应用的application.propertiesapplication.yml文件中,添加以下配置项:

spring:
  sleuth:
    sampler:
      probability: 1.0 # 配置采样概率,默认为0.1,设置为1表示采样100%

通过调整sampler.probability的值,可以灵活地控制请求的采样率。默认情况下,Spring Cloud Sleuth会根据sampler.probability的值随机决定是否对某个请求进行采样。

添加日志标志

为了在日志中打印相关的追踪信息,我们还需要在logback.xml(或其他日志配置文件)中添加一些标志,例如:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [${springAppName:-},%X{X-Trace-Id:-},%X{X-Span-Id:-},%X{X-Span-Export:-}] %logger:%L - %msg%n</pattern>
    </encoder>
</appender>

该配置用于在日志中打印追踪ID(Trace Id)、跨度ID(Span Id)和是否导出(Span Export)等信息。我们可以通过在请求头中传递这些信息来实现链路追踪。

调用其他服务

为了在服务间传递追踪信息,我们需要在调用其他服务时,将追踪ID添加到请求头中。

RestTemplate方式

如果我们在应用中使用RestTemplate来调用其他服务,可以使用RestTemplateInterceptor来自动在请求头中添加追踪ID。首先,创建一个拦截器:

import brave.propagation.ExtraFieldPropagation;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        request.getHeaders().add("X-Trace-Id", ExtraFieldPropagation.get("X-Trace-Id"));
        request.getHeaders().add("X-Span-Id", ExtraFieldPropagation.get("X-Span-Id"));
        request.getHeaders().add("X-Span-Export", ExtraFieldPropagation.get("X-Span-Export"));
        return execution.execute(request, body);
    }
}

然后,在配置类中将该拦截器添加到RestTemplate的拦截器列表中:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(new RestTemplateInterceptor());
        return restTemplate;
    }
}

现在,当我们使用RestTemplate调用其他服务时,会自动在请求头中添加追踪ID。

Feign方式

如果我们在应用中使用Feign来调用其他服务,可以通过创建一个Feign拦截器的方式在请求头中添加追踪ID。首先,创建一个拦截器:

import brave.propagation.ExtraFieldPropagation;
import feign.RequestInterceptor;
import feign.RequestTemplate;

public class FeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("X-Trace-Id", ExtraFieldPropagation.get("X-Trace-Id"));
        requestTemplate.header("X-Span-Id", ExtraFieldPropagation.get("X-Span-Id"));
        requestTemplate.header("X-Span-Export", ExtraFieldPropagation.get("X-Span-Export"));
    }
}

然后,通过注解将该拦截器添加到Feign的配置类中:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    @Bean
    public FeignInterceptor feignInterceptor() {
        return new FeignInterceptor();
    }
}

现在,当我们使用Feign调用其他服务时,会自动在请求头中添加追踪ID。

链路追踪

在配置好Spring Cloud Sleuth后,我们就可以开始链路追踪了。

首先,在我们的代码中打印日志,以便我们可以在日志中查看追踪信息。例如:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ExampleController {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExampleController.class);

    @GetMapping("/example")
    public String example() {
        LOGGER.info("Received request");
        return "Hello, World!";
    }
}

当我们发送一个请求到/api/example接口时,在日志中会显示类似以下内容的追踪信息:

15:30:45.123 [http-nio-8080-exec-1] INFO  [example-service,f805f58030ccd3fa,a7c86188f8c217c5,false] com.example.controller.ExampleController:32 - Received request

在这个例子中,我们可以看到追踪ID(f805f58030ccd3fa),跨度ID(a7c86188f8c217c5)和是否导出(false)的信息。

总结

通过使用Spring Cloud Sleuth,我们可以轻松地实现分布式追踪和链路追踪。它使我们能够在微服务架构中准确地追踪请求的流程,并更方便地进行性能分析和故障排查。希望这篇博客对你理解和使用Spring Cloud Sleuth有所帮助!


全部评论: 0

    我有话说: