Skip to content
第 229 / 250 章架构⏱ 12 分钟阅读

第 229 章:链路追踪

学习目标

  • 理解分布式调用链
  • 掌握 Sleuth 集成
  • 学会 Zipkin / SkyWalking
  • 分析性能瓶颈

一、为什么需要链路追踪

问题:用户投诉"下单慢",但不知道哪一步慢。

链路追踪:能可视化每次调用的耗时、节点、状态。

二、核心概念

2.1 Trace + Span

概念说明
Trace一次完整调用链(从入口到所有下游)
Span一个调用节点(单次方法调用)
traceId全局唯一,标识一次请求
spanId单 span 的 ID
parentId父 span 的 ID

2.2 上下文传播

通过 HTTP Header 透传:X-B3-TraceIdX-B3-SpanIdX-B3-ParentSpanId

三、Sleuth + Zipkin

3.1 Sleuth 自动埋点

Spring Cloud Sleuth 自动在以下框架埋点:

  • HTTP (RestTemplate, WebClient, OpenFeign)
  • MQ (Spring AMQP, Spring Kafka)
  • 调度任务(Scheduled)
  • 异步 (@Async)

3.2 依赖

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>

3.3 配置

yaml
spring:
  application:
    name: order-service
  zipkin:
    base-url: http://zipkin-server:9411
    sender:
      type: web
  sleuth:
    sampler:
      probability: 1.0           # 全部采样(开发)
    propagation:
      type: B3                   # Zipkin B3
    trace:
      enabled: true

3.4 启动 Zipkin

bash
docker run -d -p 9411:9411 \
  -e STORAGE_TYPE=elasticsearch \
  openzipkin/zipkin

或简化版(内存存储,重启丢失):

bash
docker run -d -p 9411:9411 openzipkin/zipkin

访问:http://localhost:9411

3.5 自定义埋点

java
@Service
@RequiredArgsConstructor
public class OrderService {

    // 通过 Sleuth 自动埋点
    private final Tracer tracer;

    public Order create(OrderRequest req) {
        // 业务前打开新 span
        Span newSpan = tracer.nextSpan().name("customProcess");
        try (Tracer.SpanInScope ws = tracer.withSpan(newSpan.start())) {
            // 自定义业务逻辑
            return process(req);
        } finally {
            newSpan.end();
        }
    }
}

或注解方式:

java
@NewSpan("customLogic")
public void process(OrderRequest req) {
    // 业务
}

@SpanTag("skuId")
public void deduct(String skuId) {
    // 自动打 tag
}

四、SkyWalking

4.1 简介

Apache SkyWalking 是国产开源的 APM,功能比 Sleuth+Zipkin 更强。

4.2 服务端部署

yaml
# docker-compose.yml
services:
  skywalking-oap:
    image: apache/skywalking-oap-server:9.7.0
    ports: ["11800:11800", "12800:12800"]
    environment:
      SW_STORAGE: elasticsearch
      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200

  skywalking-ui:
    image: apache/skywalking-ui:9.7.0
    ports: ["8080:8080"]
    depends_on:
      - skywalking-oap

  elasticsearch:
    image: elasticsearch:7.17.10
    environment:
      discovery.type: single-node
    ports: ["9200:9200"]

4.3 客户端(Java Agent)

无需改代码,在启动命令加探针:

bash
java -javaagent:/opt/skywalking/agent/skywalking-agent.jar \
     -Dskywalking.agent.service_name=order-service \
     -Dskywalking.collector.backend_service=127.0.0.1:11800 \
     -jar order-service.jar

K8s 中通过 sidecar 注入。

4.4 关键能力

服务拓扑

链路追踪

每个请求一行展示,鼠标悬停看详情。

慢 SQL

sql
SELECT * FROM big_table
WHERE create_at > ?
  AND status = 'ACTIVE'

SkyWalking 自动捕获执行时间。

告警

3 分钟内某接口 P99 > 500ms
5 分钟内某服务错误率 > 5%

配置 webhook 通知。

4.5 OpenTelemetry(下一代标准)

xml
<dependency>
    <groupId>io.opentelemetry.javaagent</groupId>
    <artifactId>opentelemetry-javaagent</artifactId>
</dependency>
bash
java -javaagent:opentelemetry-javaagent.jar \
     -Dotel.exporter.otlp.endpoint=http://collector:4317 \
     -jar app.jar

支持多后端:Jaeger / Tempo / Zipkin 等。

五、追踪与日志结合

5.1 日志中带 traceId

xml
<!-- logstash-logback 依赖 -->
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
</dependency>

logback-spring.xml:

xml
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeMdcKeyName>traceId</includeMdcKeyName>
            <includeMdcKeyName>spanId</includeMdcKeyName>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

输出:

json
{
  "timestamp": "2026-08-13T10:30:00.000+08:00",
  "level": "INFO",
  "message": "创建订单",
  "traceId": "abc123",
  "spanId": "1",
  "service": "order-service"
}

5.2 在 Kibana/Grafana Loki 通过 traceId 查询

traceId:abc123

5.3 反向跳转

Trace UI → 点击 span → 直接跳转到日志平台查同一 traceId。

六、性能分析

6.1 P99 定位

6.2 服务地图

一眼看出库存是瓶颈。

6.3 调用频率

GET /api/orders  QPS 1000  P99 80ms   ✅
GET /api/order/{id}  QPS 50  P99 200ms ⚠️

七、自研埋点(Brave)

不依赖 Spring Cloud Sleuth,直接用 Zipkin Brave。

xml
<dependency>
    <groupId>io.zipkin.brave</groupId>
    <artifactId>brave</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
</dependency>
java
@Configuration
public class TraceConfig {

    @Bean
    public Brave brave() {
        Sender sender = OkHttpSender.create("http://zipkin:9411/api/v2/spans");
        AsyncReporter reporter = AsyncReporter.create(sender);
        Brave brave = new Brave.Builder("order-service")
            .reporter(reporter)
            .traceSampler(Sampler.ALWAYS_SAMPLE)
            .build();
        return brave;
    }
}

八、采样策略

8.1 全量 vs 概率

yaml
spring:
  sleuth:
    sampler:
      probability: 0.1    # 10% 采样

8.2 尾部采样(高级)

只在追踪结束时决定是否上报。

yaml
# Zipkin 用 Brave 时启用
zipkin:
  async:
    enabled: true

8.3 强制采样(关键路径)

java
@Sampled
public void criticalRequest() {
    // 强制采样
}

九、与 OpenTelemetry 对接

9.1 当前格局

  • Sleuth → Zipkin / 隐退
  • OpenTelemetry → 后起之秀,统一标准
  • SkyWalking → 自有体系

9.2 OTel 优势

  • CNCF 主导
  • 多语言支持
  • 与厂商无关

9.3 迁移建议

xml
<!-- 兼容方案:Sleuth + OTel Bridge -->
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>

十、本章小结

工具特点
Sleuth + ZipkinSpring 全家桶,轻量
SkyWalking国产,功能强
OpenTelemetry标准,云原生
自研 Brave灵活,代码可控

动手练习

  1. 部署 Zipkin,Spring Boot 自动埋点,启动两个服务互相调用
  2. 自定义 @NewSpan 标记业务方法
  3. 在日志中输出 traceId,通过日志平台查询
  4. 用 SkyWalking Agent 接 Java 应用,看服务拓扑图

推荐阅读


下一章:第 230 章:微服务安全

本站基于 VitePress 构建 · 由 Codebook 团队维护