You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:57:13