Spring Cloud Sleuth TraceID跨微服务传递失败,请求排查方案
问题场景
使用Spring Boot 2.7.5 + Spring Cloud 2021.0.4(Jubilee版本)搭建微服务,通过RestTemplate调用另一微服务时,发起方生成的Sleuth TraceID未能传递到被调用服务的日志中,调用代码如下:
RestTemplate restTemplate = new RestTemplate(); logger.info("ApplicationController: controllerMessage() called: " + properties.getType() + " " + properties2.getMode()); String uri = "http://localhost:8089/poc1/message"; HttpHeaders headers = new HttpHeaders(); HttpEntity request = new HttpEntity(headers); ResponseEntity<String> response = restTemplate.exchange( uri, HttpMethod.GET, request, String.class );
核心原因
手动new RestTemplate()的方式会绕过Spring Cloud Sleuth的自动增强机制。Sleuth需要通过拦截器包装RestTemplate,才能在HTTP请求头中注入X-B3-TraceId、X-B3-SpanId等链路追踪标识,而手动实例化的RestTemplate不会被这些拦截器处理,导致TraceID无法传递。
解决方案
1. 使用Spring容器管理的RestTemplate实例
不要手动new RestTemplate,改为通过RestTemplateBuilder构建并注入,或者直接声明Bean:
// 在配置类(@Configuration)或组件中定义RestTemplate Bean @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder.build(); }
然后在控制器中通过@Autowired注入使用:
@Autowired private RestTemplate restTemplate; // 调用代码保持逻辑不变,去掉手动new的部分 logger.info("ApplicationController: controllerMessage() called: " + properties.getType() + " " + properties2.getMode()); String uri = "http://localhost:8089/poc1/message"; HttpHeaders headers = new HttpHeaders(); HttpEntity request = new HttpEntity(headers); ResponseEntity<String> response = restTemplate.exchange( uri, HttpMethod.GET, request, String.class );
如果你的服务使用了服务发现(如Eureka、Nacos),可以给RestTemplate Bean添加@LoadBalanced注解,支持服务名调用,这也不影响Sleuth的链路传递。
2. 确认依赖配置正确
检查项目依赖是否包含Sleuth和Zipkin的starter:
Maven pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
Gradle build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth' implementation 'org.springframework.cloud:spring-cloud-starter-zipkin'
3. 基础配置校验
确保两个服务的application.properties(或application.yml)中开启Sleuth并配置Zipkin:
# 开启Sleuth(默认已开启,显式配置更清晰) spring.sleuth.enabled=true # Zipkin服务器地址(根据你的实际部署调整) spring.zipkin.base-url=http://localhost:9411/
4. 确保日志格式包含TraceID
两个服务都需要配置日志格式,将TraceID和SpanID打印到日志中,比如在logback-spring.xml中配置:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId},%X{spanId}] %logger{36} - %msg%n</pattern> </encoder> </appender>
或者通过application.properties配置:
logging.pattern.level=%5p [%X{traceId:-},%X{spanId:-}]
验证
重启两个服务后发起调用,检查被调用服务的日志,应该能看到和发起方一致的TraceID。
内容的提问来源于stack exchange,提问作者win32trojan

