第 9 章 · 链路追踪与可观测性
本章目标:在 svc-spring-demo 全链路集成 Micrometer Tracing(OpenTelemetry Bridge);让 traceId / spanId 贯穿 Gateway → BFF → Feign → 各业务服务;对接 Zipkin 或 Jaeger 可视化;将追踪与 结构化日志 MDC、Actuator 指标关联;建立微服务 RED 方法巡检清单。可与 spring-boot-web ch18 对照学习。
学时建议:5~6 小时(含 2 小时 Zipkin + 全服务联调)
前置:spring-cloud-web ch01~ch08;spring-boot-web ch09 MDC 与 ch18 Actuator/Prometheus 概念。
9.1 微服务为何更需要 Tracing
单体 shop-spring-demo 一次请求在一个进程内完成;svc-spring-demo 一次下单可能经过:
Gateway → order-svc → Feign → product-svc
→ Feign → inventory-svc
→ Stream → RabbitMQ → notify-svc
| 无追踪 | 有追踪 |
|---|---|
| 各服务日志 traceId 不一致 | 同一 traceId 串联 |
| 慢请求不知卡在哪一跳 | Span 树定位瓶颈 |
| 故障复盘靠猜 | 按 X-B3 / W3C 头还原路径 |
可观测性三大支柱(Metrics / Logs / Traces)在微服务中需统一 traceId 关联。
9.2 依赖与版本(父 POM)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bom</artifactId>
<version>1.2.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
各服务(含 gateway-svc、bff-svc、order-svc 等)添加:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Gateway 使用 WebFlux,同样支持 Micrometer Tracing;勿混用已废弃的 Spring Cloud Sleuth 3.x 文档。
9.3 统一配置(Nacos 共享)
svc-tracing.yaml(各服务 spring.config.import 引入):
management:
tracing:
sampling:
probability: 1.0 # 教学全采样;生产调低如 0.1
zipkin:
tracing:
endpoint: http://zipkin.example.com:9411/api/v2/spans
logging:
pattern:
level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}]"
本地等价:http://127.0.0.1:9411。
Docker 启动 Zipkin:
# docker-compose.tracing.yml
services:
zipkin:
image: openzipkin/zipkin:2.24
ports: ["9411:9411"]
9.4 Gateway 传播上下文
Spring Cloud Gateway 自动注入 W3C traceparent 与 B3 头转发到下游。确认未手动剥离:
spring:
cloud:
gateway:
default-filters:
- name: Retry
args:
retries: 0 # 教学关闭,避免追踪重复 span 干扰理解
自定义全局过滤器(可选,记录入口 span 属性):
@Component
public class TraceAttributeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put("gateway.route.id",
exchange.getAttribute(GATEWAY_ROUTE_ATTR));
return chain.filter(exchange);
}
@Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 10; }
}
9.5 Feign 与 TraceId 传播
ch04 手写 X-Trace-Id 拦截器在引入 Micrometer Tracing 后可移除——框架自动传播。保留用于日志关联即可:
@Slf4j
@Component
public class LoggingFeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String traceId = MDC.get("traceId");
if (traceId != null) {
log.debug("Feign {} traceId={}", template.url(), traceId);
}
}
}
验证:在 Zipkin UI 搜索 serviceName=order-svc,应看到子 Span product-svc。