Spring Boot 3.3.2下WebClient的Micrometer链路追踪传播失效问题
Spring Boot 3.3.2 链路追踪问题:WebClient调用TraceId不传播
问题现象
使用WebClient调用其他微服务时,TraceId无法正常传播,每次请求会生成新的TraceId:
- api-gateway -> order-service:两者TraceId一致
- order-service -> inventory-service:inventory-service的TraceId与上游不一致
相关配置代码
API网关安全配置
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http.csrf(ServerHttpSecurity.CsrfSpec::disable) .authorizeExchange(exchange -> exchange.pathMatchers("/eureka/**") .permitAll() .anyExchange().authenticated()) .oauth2ResourceServer(jwt -> jwt.jwt(Customizer.withDefaults())); return http.build(); } }
Order服务中WebClient调用Inventory服务的代码(方法已标注@Observed)
InventoryResponse[] inventoryResponses; inventoryResponses = webClientBuilder.build().get() .uri("http://inventory-service/api/inventory", uriBuilder -> uriBuilder.queryParams(multiValueMap).build()) .retrieve() .bodyToMono(InventoryResponse[].class) .block();
Inventory服务核心方法(已标注@Observed)
@Observed(name = "order.name", contextualName = "Inventory calls DB") @Transactional(readOnly = true) public List<InventoryResponse> isInStock(Map<String, String> skuCodes) { Map<String, Integer> skuCodesToInteger = new HashMap<>(); for (Map.Entry<String, String> entry : skuCodes.entrySet()) { try { int value = Integer.parseInt(String.valueOf(entry.getValue())); skuCodesToInteger.put(entry.getKey(), value); } catch (NumberFormatException e) { log.error("Cannot cast {} to Integer", entry.getValue()); } } log.info("Checking stock inventory"); return inventoryRepository.findBySkuCodeIn(skuCodesToInteger.keySet() .stream() .toList()) .stream() .map(inventory -> InventoryResponse .builder() .isInStock(inventory.getQuantity() >= skuCodesToInteger.get(inventory.getSkuCode())) .skuCode(inventory.getSkuCode()) .build()).toList(); }
WebClient配置类
@Configuration public class WebClientConfig { @Bean @LoadBalanced public WebClient.Builder webClientBuilder() { return WebClient.builder(); } }
RestTemplate对比测试
改用RestTemplate调用时,链路追踪正常,TraceId全程一致:
RestTemplate配置
@Configuration public class RestTemplateConfiguration { @LoadBalanced @Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder.build(); } }
Order服务中RestTemplate调用Inventory服务的代码(方法已标注@Observed)
URI uri = UriComponentsBuilder .fromUriString("http://inventory-service/api/inventory") .queryParams(multiValueMap).build().toUri(); InventoryResponse[] inventoryResponses = restTemplate .getForObject(uri, InventoryResponse[].class);
疑问
是否必须使用WebClient?还是可以改用RestTemplate?该问题的根本原因是什么?
更新内容
感谢@brian-clozel的提示,调整WebClient Bean配置后,TraceId可以正常传播,但此时如果使用服务名(http://inventory-service/api/inventory)调用会出现DNS解析失败错误:
2024-08-04T20:25:25.651+03:00 ERROR 1019862 --- [order-service] [nio-8081-exec-2] [order-service,,]o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception io.netty.resolver.dns.DnsErrorCauseException: Query failed with SERVFAIL at io.netty.resolver.dns.DnsResolveContext.onResponse(..)(Unknown Source) ~[netty-resolver-dns-4.1.111.Final.jar:4.1.111.Final] 2024-08-04T20:25:25.654+03:00 ERROR 1019862 --- [order-service] [nio-8081-exec-2] [order-service,,]o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.web.reactive.function.client.WebClientRequestException: Failed to resolve 'inventory-service' [A(1), AAAA(28)] after 2 queries ] with root cause io.netty.resolver.dns.DnsErrorCauseException: Query failed with SERVFAIL at io.netty.resolver.dns.DnsResolveContext.onResponse(..)(Unknown Source) ~[netty-resolver-dns-4.1.111.Final.jar:4.1.111.Final]
为解决服务名调用的问题,给WebClient添加了负载均衡过滤器,最终配置如下:
@Configuration @Slf4j @RequiredArgsConstructor public class WebClientConfig { private final ReactorLoadBalancerExchangeFilterFunction lbFunction; @Bean public WebClient webClient(WebClient.Builder webClientBuilder) { return webClientBuilder .filter(lbFunction) .build(); } }
内容的提问来源于stack exchange,提问作者KnOMM
相关产品推荐
相关产品推荐

