Zipkin 面试题
10 道题- 分类
- 可观测性
- 子分类
- trace
- 题目数
- 10 道
1 Zipkin 的核心架构由哪些组件组成?各组件的职责是什么?
答案:
Zipkin 是 Twitter 开源的分布式追踪系统(受 Google Dapper 论文启发),用于收集微服务架构中的时序数据,解决服务依赖分析与延迟问题。
核心组件:
| 组件 | 职责 | 部署形态 |
|---|---|---|
| Reporter | 客户端埋点库 | 集成在应用中(brave / zipkin-js) |
| Collector | 数据收集与校验 | 无状态服务,可水平扩展 |
| Storage | 后端存储 | In-Memory / MySQL / Cassandra / Elasticsearch |
| Query Service | 查询 API | 提供 JSON API 给 UI |
| Web UI | 可视化界面 | 依赖图、Trace 时间线、Span 详情 |
数据流:
应用 (Instrumentation)
│
├── Reporter.send(span) ── HTTP POST /api/v2/spans
│
▼
Zipkin Collector
│
├── 校验 traceId / spanId 格式
├── 写入 SpanStore
│
▼
Storage (Cassandra / ES / MySQL)
│
▼
Query Service ◄── Web UI (GET /api/v2/trace/{id})
All-in-One 启动(开发模式):
docker run -d --name zipkin \
-p 9411:9411 \
openzipkin/zipkin
Web UI 默认端口 9411,API 端点 /api/v2/spans(v2 协议)。
2 Zipkin 的数据模型:Span、Trace、Annotation 和 Tag 的关系是什么?
答案:
Zipkin 数据模型受 Google Dapper 启发,与 OpenTracing / OpenTelemetry 兼容,核心实体为 Span,通过共享 traceId 构成完整 Trace。
数据模型层次:
flowchart TB
T["Trace
traceId=0af7651916cd43dd"]
T --> SA["Span A
Root: HTTP GET /api/orders
id: b7ad6b7169203331
kind: SERVER"]
SA --> SA_T["Tags: http.method=GET
duration: 250000μs"]
SA --> SB["Span B
Child: SELECT FROM orders
parentId: b7ad6b7169203331
kind: CLIENT"]
SB --> SB_T["Tags: db.statement: SELECT..."]
SA --> SC["Span C
Child: HTTP call to payment
parentId: b7ad6b7169203331
kind: CLIENT"]
SC --> SC_T["remoteEndpoint: payment-service"]
Span 关键字段:
| 字段 | 含义 | 示例 |
|---|---|---|
| traceId | Trace 全局唯一 ID(16 或 32 字节十六进制) | 0af7651916cd43dd |
| id | Span 唯一 ID | b7ad6b7169203331 |
| parentId | 父 Span ID(Root Span 为 null) | b7ad6b7169203331 |
| kind | Span 类型枚举 | CLIENT / SERVER / PRODUCER / CONSUMER |
| name | 操作名 | GET /api/orders |
| timestamp | 起始时间(微秒) | 1716700000000000 |
| duration | 持续时长(微秒) | 250000 |
| localEndpoint | 本地服务标识 | {serviceName: "api-gateway"} |
| remoteEndpoint | 远端服务标识 | {serviceName: "payment-service"} |
| tags | 键值对标签(可搜索) | http.method=GET |
| annotations | 时间戳事件 | sr / ss / cs / cr |
Annotation 类型:
| 值 | 含义 | 角色 |
|---|---|---|
| cs | Client Send | 客户端发起请求 |
| cr | Client Receive | 客户端收到响应 |
| ss | Server Send | 服务端发送响应 |
| sr | Server Receive | 服务端收到请求 |
| ms | Message Send | MQ 生产者 |
| mr | Message Receive | MQ 消费者 |
| ws / wr | Wire Send / Receive | 网络边界事件 |
3 Zipkin 支持哪些采样策略?如何选择与配置?
答案:
Zipkin 默认 100% 上报,生产环境为降低存储与网络开销,需要在 Reporter 层配置采样器(Tracing.Builder.sampler(...))。
采样策略对比:
| 采样器 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| AlwaysSampler | 100% 全量采集 | 开发、测试、压测 | 生产成本爆炸 |
| NeverSampler | 完全不采集 | 临时关闭追踪 | 无法排查问题 |
| PercentageBasedSampler | 概率采样(0.0~1.0) | 通用生产环境 | 突发流量统计偏差 |
| RateLimitingSampler | 令牌桶限速(每秒 N 条) | 流量稳定的关键链路 | 突发流量易丢采样 |
| BoundarySampler | 首个 Span 概率决定整条 Trace | 保持 Trace 完整性 | 长尾 Trace 部分缺失 |
Brave(Brave 5.x,Java 客户端)配置:
@Bean
public Brave brave() {
return new Brave.Builder("order-service")
.traceSampler(Sampler.ALWAYS_SAMPLE) // 全量
// 或
.traceSampler(Sampler.NEVER_SAMPLE)
// 或自定义
.traceSampler(rateLimitingSampler(10)) // 10 req/s
.build();
}
Spring Boot Sleuth 集成配置(application.yml):
spring:
sleuth:
sampler:
probability: 0.1 # 10% 概率采样
propagation:
type: B3 # B3 协议(默认)
BoundarySampler 实现 Trace 完整性:
public class BoundarySampler extends Sampler {
private final Sampler delegate;
@Override
public boolean isSampled(TraceContext traceContext) {
// 根 Span 决策,整条 Trace 保持一致
if (traceContext.parentId() == null) {
return delegate.isSampled(traceContext);
}
return traceContext.sampled() != null && traceContext.sampled();
}
}
最佳实践:
- 核心交易链路使用 100% 或高概率(>=10%),次要链路 1% ~ 5%。
- 高 QPS 场景使用 RateLimitingSampler,避免 Collector 过载。
- 多服务调用链使用 BoundarySampler,确保 Trace ID 一致且决策统一。
4 Zipkin 与 Jaeger 的核心差异是什么?如何在生产环境中选型?
答案:
Zipkin 与 Jaeger 同源(Dapper 思想),但由不同组织演进,二者在架构、协议、存储与生态上差异显著。
核心对比:
| 维度 | Zipkin | Jaeger |
|---|---|---|
| 起源 | Twitter(2012) | Uber(2015),CNCF 毕业 |
| 架构 | 直接上报 Collector | Client SDK → Agent(UDP)→ Collector |
| 传输 | HTTP/JSON、Kafka、gRPC | UDP(Thrift)、HTTP、gRPC |
| 采样 | 客户端决策 | 客户端 + Agent 集中决策 |
| 存储 | MySQL / Cassandra / ES | Cassandra / ES / Kafka + Badger |
| 依赖分析 | 仅 UI 展示 | 内置 sparkline + Graph 拓扑 |
| 协议 | B3(Zipkin 原生)、W3C TraceContext | Jaeger Thrift、W3C TraceContext |
| UI 体验 | 简洁、Trace 时间线清晰 | 依赖图、Service 拓扑、Metrics 集成 |
| 语言生态 | Java/Go/Node/Python/Go 官方库 | Go/Node/Python/Java/.NET 官方库 |
| 生产成熟度 | Twitter 规模验证 | Uber 规模验证,CNCF 标杆 |
| 运维成本 | 低(All-in-One 单 jar) | 中(多组件 + Kafka 缓冲) |
架构差异示意:
Zipkin:
App → Reporter (HTTP POST) → Collector → Storage → UI
Jaeger (生产级):
App → Jaeger Client → Agent (UDP **6831/6832**) → Collector → Kafka → Ingester → Storage → UI
↑ ↑
缓冲削峰 异步消费
选型决策:
| 场景 | 选型 | 理由 |
|---|---|---|
| Spring Cloud 微服务 | Zipkin | Sleuth 原生集成,零侵入 |
| Kubernetes + gRPC | Jaeger | Agent UDP 模式低开销,OTel 标准 |
| 需要依赖拓扑分析 | Jaeger | 内置 Service Graph 视图 |
| 极简部署、低运维 | Zipkin | 单 jar 启动,All-in-One |
| 多语言(Go/Node/Py) | Jaeger | 各语言官方 Client 更完善 |
| 未来迁移 OTel | 两者皆可 | 都已适配 OpenTelemetry 协议 |
| 超大规模(> 10w QPS) | Jaeger + Kafka | Agent + Kafka 削峰能力强 |
共同趋势:
- 两者都向 OpenTelemetry 收敛,OTel 成为数据采集标准。
- Jaeger 后端已支持接收 OTel 协议,Zipkin 同样可桥接。
- 新项目推荐 OTel SDK + Jaeger / Tempo 后端,Zipkin 适合存量 Spring Cloud 体系。
5 Zipkin 的存储后端有哪些?各自适用什么场景?
答案:
Zipkin 通过 SpanStore 接口抽象存储层,支持多种后端实现,生产环境选型需结合数据量、查询性能与运维成本。
存储后端对比:
| 存储 | 数据规模 | 查询性能 | 写入吞吐 | 运维成本 | 适用场景 |
|---|---|---|---|---|---|
| In-Memory | 小(< 10万 Span) | 极快 | 极快 | 零 | 开发测试 |
| MySQL | 中(百万级) | 中 | 中 | 低 | 中小规模、已有 MySQL 集群 |
| PostgreSQL | 中(百万级) | 中 | 中 | 低 | 已有 PG 集群 |
| Cassandra | 大(亿级) | 高 | 极高 | 中高 | 大规模生产、Twitter 原始选择 |
| Elasticsearch | 大(亿级) | 高(全文检索) | 高 | 中 | 复杂查询、已有 ES 集群 |
MySQL Schema(V2):
CREATE TABLE zipkin_spans (
trace_id_high BIGINT NOT NULL,
trace_id BIGINT NOT NULL,
id BIGINT NOT NULL,
parent_id BIGINT,
name VARCHAR(255),
kind VARCHAR(10),
timestamp BIGINT,
duration BIGINT,
PRIMARY KEY (trace_id_high, trace_id, id, kind)
);
CREATE TABLE zipkin_annotations (
trace_id_high BIGINT NOT NULL,
trace_id BIGINT NOT NULL,
span_id BIGINT NOT NULL,
a_key VARCHAR(255) NOT NULL,
a_value TEXT,
a_type INT,
endpoint_service_name VARCHAR(255),
PRIMARY KEY (trace_id_high, trace_id, span_id, a_key, timestamp)
);
CREATE INDEX idx_zipkin_annotations_ts
ON zipkin_annotations (endpoint_service_name, a_type, trace_id_high, trace_id, span_id);
Elasticsearch 索引模板:
# 启动 Zipkin + ES
docker run -d --name zipkin \
-e STORAGE_TYPE=elasticsearch \
-e ES_HOSTS=http://es:9200 \
-p 9411:9411 \
openzipkin/zipkin
ES 自动按天创建索引 zipkin:span-2026-06-06,支持按 serviceName、tags.http.method 等检索。
Cassandra 适用场景:
- Twitter 内部使用,Cassandra 是 Zipkin 最初的"原生"存储。
- 写入吞吐量高(百万级 Span/s),适合大流量生产。
- 缺点:Schema 设计宽列,二次查询需建二级索引。
选型决策:
| 业务量级 | 推荐存储 |
|---|---|
| < 1k TPS | In-Memory / MySQL |
| 1k ~ 10k TPS | MySQL / PostgreSQL |
| 10k ~ 100k TPS | Elasticsearch |
| > 100k TPS | Cassandra + Kafka 缓冲 |
6 如何在 Spring Cloud 微服务中集成 Zipkin?关键配置有哪些?
答案:
Spring Cloud Sleuth(已合并至 Micrometer Tracing)是 Spring 生态与 Zipkin 的官方集成方案,通过自动埋点 + 少量配置即可接入。
核心依赖(Spring Boot 2.x + Sleuth):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- Web 组件自动埋点 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot 3.x + Micrometer Tracing:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
配置文件(application.yml):
spring:
application:
name: order-service # 必填,对应 Zipkin localEndpoint.serviceName
zipkin:
base-url: http://zipkin:9411
sender:
type: web # web / kafka / rabbit
compression-enabled: true # gzip 压缩,减少网络带宽
sleuth:
sampler:
probability: 0.1 # 10% 采样
propagation:
type: B3 # 跨服务传递协议
enabled: true
自动埋点覆盖范围:
| 组件 | 是否埋点 | 备注 |
|---|---|---|
| Spring MVC | 是 | 每次 HTTP 调用生成 Span |
| RestTemplate | 是 | 通过 RestTemplateInterceptor |
| OpenFeign | 是 | 自动传递 Header |
| WebClient | 是 | 响应式链路追踪 |
| Spring Scheduling | 是 | 定时任务 Span |
| Spring Messaging | 是 | MQ 消费 Span |
| JdbcTemplate | 是(需开启) | 慢 SQL 检测 |
| Kafka | 是 | 消费者 Producer Span |
| RabbitMQ | 是 | Producer/Consumer 双向 |
自定义 Span:
@Autowired
private Tracer tracer;
public void processOrder(Order order) {
Span newSpan = tracer.nextSpan().name("validate-inventory").start();
try (Tracer.SpanInScope ws = tracer.withSpan(newSpan)) {
// 业务逻辑
newSpan.tag("order.id", order.getId());
inventoryService.check(order);
} catch (Exception e) {
newSpan.error(e);
} finally {
newSpan.end();
}
}
自定义 Tag 与 Log:
span.tag("user.id", userId); // 搜索时可按 user.id 过滤
span.event("cache.miss"); // 事件记录
span.error(exception); // 自动记录异常堆栈
生产最佳实践:
- 统一
spring.application.name,确保 Zipkin UI 区分服务。 - 使用
probability: 0.1起步,根据存储成本调整。 - 高吞吐场景切换
sender.type: kafka,避免同步 HTTP 阻塞业务线程。 - 开启
compression-enabled: true,Span 数据 gzip 后带宽下降 60%+。
7 什么是 B3 协议?B3 与 W3C TraceContext 的核心区别是什么?
答案:
B3(BigBrotherBird)是 Zipkin 定义的跨服务追踪上下文传播协议,规定了 HTTP Headers 在服务间如何传递 traceId、spanId、采样决策等字段。
B3 Header 完整字段:
| Header | 含义 | 示例 |
|---|---|---|
| X-B3-TraceId | Trace 全局 ID(Hex,16 或 32 字节) | 0af7651916cd43dd8448eb211c80319 |
| X-B3-SpanId | 当前 Span ID | b7ad6b7169203331 |
| X-B3-ParentSpanId | 父 Span ID(Root 时不传递) | 00f067aa0ba902b7 |
| X-B3-Sampled | 采样决策 | 1(采样) / 0(不采样) |
| X-B3-Flags | 调试标志 | 1(强制采样) / 0 |
| b3 | 复合 Header(单 Header 模式) | 0af7651916cd43dd-b7ad6b7169203331-1 |
B3 单 Header 模式(b3):
b3: 0af7651916cd43dd-b7ad6b7169203331-8448eb211c80319-1
│ │ │ │
│ │ │ └─ Sampled (0/1/d)
│ │ └─ Parent Span ID (可选)
│ └─ Span ID
└─ Trace ID
W3C TraceContext 协议:
| Header | 含义 | 示例 |
|---|---|---|
| traceparent | Trace + Span + Flags | 00-0af7651916cd43dd8448eb211c80319-b7ad6b7169203331-01 |
| tracestate | 厂商扩展字段 | congo=t61rcWkgMzE,rojo=00f067aa0ba902b7 |
| tracestate: 格式 | vendor=value | 多个 vendor 用逗号分隔 |
核心对比:
| 维度 | B3 | W3C TraceContext |
|---|---|---|
| 标准方 | Zipkin / Twitter | W3C(行业标准) |
| 版本 | Zipkin 1.x 起 | 2020 年正式发布 |
| 多 Vendor 协作 | 不支持 | tracestate 支持多厂商上下文 |
| Header 数量 | 最多 5 个 B3 Header 或 1 个 b3 | 固定 1 个 traceparent + tracestate |
| TraceID 长度 | 16 / 32 字节可选 | 固定 32 字节(128 bit) |
| SpanID 长度 | 8 字节(64 bit) | 8 字节(64 bit) |
| 兼容性 | 主流框架均支持 | 新框架默认采用 |
| OpenTelemetry | 支持 | 默认协议 |
B3 与 W3C 共存方案:
# Spring Boot 同时启用 B3 与 W3C
spring:
sleuth:
propagation:
type: B3,W3C # 双协议注入,按 Header 优先级解析
跨协议桥接(OpenTelemetry Collector):
# otel-collector-config.yaml
receivers:
zipkin:
endpoint: 0.0.0.0:9411
exporters:
otlp:
endpoint: jaeger:4317
service:
pipelines:
traces:
receivers: [zipkin]
exporters: [otlp]
通过 Collector 将 B3 上报转换为 W3C 协议,写入 Jaeger / Tempo 后端,实现协议统一。
8 Zipkin 如何与 OpenTelemetry 集成?迁移路径如何设计?
答案:
OpenTelemetry(OTel)是 CNCF 主导的可观测性数据采集统一标准,Zipkin 既是 OTel 的协议实现之一,也是 OTel 可桥接的目标后端。
集成方式一:Zipkin 作为 OTel Exporter
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
SpanExporter zipkinExporter = ZipkinSpanExporter.builder()
.setEndpoint("http://zipkin:9411/api/v2/spans")
.build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(zipkinExporter))
.build();
集成方式二:OTel Collector 桥接 Zipkin(生产推荐)
# otel-collector 配置
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
zipkin:
endpoint: http://zipkin:9411/api/v2/spans
format: json
service:
pipelines:
traces:
receivers: [otlp]
exporters: [zipkin]
应用使用 OTel SDK 上报到 Collector,Collector 转换为 Zipkin JSON 协议后写入 Zipkin 后端。
集成方式三:Zipkin Bridge 反向接收 OTel 数据
// 使用 zipkin-reporter-otel
@Bean
public Reporter<Span> zipkinReporter() {
return OpenTelemetrySpanExporter.create("http://zipkin:9411/api/v2/spans");
}
迁移路径设计:
阶段 1: 现状评估
├── 列出所有使用 Zipkin 客户端的服务
├── 统计 SDK 版本、协议类型(B3 / Thrift)
└── 评估存储后端类型与数据量
阶段 2: 引入 OTel SDK(双写过渡)
├── 应用层 OTel SDK 初始化
├── 保留 zipkin-reporter 兼容旧版
├── 部署 OTel Collector 接收 OTLP
└── 灰度 10% 流量验证数据一致性
阶段 3: 协议统一
├── 全量切流 OTel SDK
├── 通过 Collector 桥接至 Zipkin
├── 验证 traceId / spanId / parentId 一致
└── 关闭 zipkin-reporter 直连
阶段 4: 后端演进
├── 保留 Zipkin(成本低、UI 简洁)
├── 或迁移至 Jaeger / Tempo(OTel 原生)
└── 长期方案:OTel SDK + Tempo + Grafana
关键注意事项:
- B3 与 W3C TraceContext 协议不同,迁移时需在 Header 注入层做兼容。
- Zipkin 1.x 与 2.x 协议格式差异(
/api/v1/spansvs/api/v2/spans),OTel Exporter 默认走 v2。 - TraceId 长度变化:B3 16 字节 → W3C 32 字节,需确保存储后端 Schema 兼容。
- 已使用 Spring Cloud Sleuth 的项目,建议直接升级到 Micrometer Tracing,避免重写埋点。
9 Zipkin 在生产环境中有哪些常见的性能瓶颈与优化手段?
答案:
Zipkin 架构简单,但生产高 QPS 场景下仍可能遇到 Collector 单点、存储写入慢、查询超时等问题,需要从采集、传输、存储、查询四个环节分别优化。
生产瓶颈与解决方案:
| 瓶颈 | 现象 | 根因 | 解决方案 |
|---|---|---|---|
| Collector 过载 | 业务线程阻塞,HTTP 503 | 同步阻塞式入库 | 引入 Kafka / RabbitMQ 缓冲 |
| 存储写入慢 | Collector 队列堆积 | MySQL 单库写入瓶颈 | 切换 ES / Cassandra,或水平分库 |
| 采样率过高 | 存储成本爆炸 | 100% 全量采集 | 概率采样 1% ~ 10% |
| 网络带宽 | 跨机房带宽打满 | Span 体积大 | gzip 压缩 + 精简 Tags |
| 查询慢 | UI 加载超时 | 全表扫描、索引缺失 | 存储后端加索引(serviceName + time) |
| Span 风暴 | 突发流量击穿 | 错误重试循环 | RateLimiting + 熔断 |
| 依赖图加载慢 | UI 卡顿 | Trace 数量过多 | 按 Service + Time 范围限制 |
Kafka 缓冲架构(生产推荐):
# Zipkin Server 启动配置
STORAGE_TYPE=elasticsearch
ES_HOSTS=http://es:9200
# Collector 端通过 Kafka 异步上报
KAFKA_BOOTSTRAP_SERVERS=kafka:9092
KAFKA_TOPIC=zipkin-spans
ZIPKIN_COLLECTOR_KAFKA_ENABLED=true
// 应用端配置(Spring Boot)
spring:
zipkin:
sender:
type: kafka
kafka:
bootstrap-servers: kafka:9092
topic: zipkin-spans
采样与埋点优化:
// 1. 自适应采样:核心接口高概率,非核心低概率
@Bean
public Sampler customSampler() {
return new CompositeSampler()
.add("/api/payment/**", 1.0) // 支付链路 100%
.add("/api/health", 0.0) // 健康检查 0%
.defaultRate(0.05); // 其他 5%
}
// 2. 精简 Tags,避免记录敏感与冗余信息
span.tag("order.id", order.getId());
// 不要做:
// span.tag("request.body", jsonString); // 体积大、可能含敏感数据
存储后端优化(Elasticsearch 为例):
// 索引模板
{
"index_patterns": ["zipkin:span-*"],
"settings": {
"number_of_shards": 6,
"number_of_replicas": 1,
"refresh_interval": "10s"
},
"mappings": {
"properties": {
"traceId": { "type": "keyword" },
"name": { "type": "keyword" },
"timestamp_millis": { "type": "long", "index": false },
"tags": { "type": "object", "dynamic": true }
}
}
}
- 按天滚动索引,避免单索引过大。
traceId、name用keyword不分词,节省空间。- 配置 ILM 自动删除 7 天前数据。
Collector 水平扩展:
# 部署多个 Zipkin Collector 实例
apiVersion: apps/v1
kind: Deployment
metadata:
name: zipkin-collector
spec:
replicas: 3
template:
spec:
containers:
- name: zipkin
image: openzipkin/zipkin
env:
- name: STORAGE_TYPE
value: elasticsearch
- name: ES_HOSTS
value: http://es:9200
通过 K8s Service 对外暴露,应用通过 DNS 负载均衡到多个 Collector 实例。
容量规划参考:
| QPS | 采样率 | 日均 Span | 存储(30d) | 推荐后端 |
|---|---|---|---|---|
| 1,000 | 10% | 8.6 亿 | ~500 GB | MySQL / PG |
| 10,000 | 5% | 4.3 亿 | ~300 GB | ES(3 节点) |
| 100,000 | 1% | 8.6 亿 | ~600 GB | ES(6 节点)/ Cassandra |
| 1,000,000 | 0.5% | 43 亿 | ~3 TB | Cassandra + Kafka |
10 Zipkin 在生产中的典型故障排查案例有哪些?
答案:
Zipkin 在微服务架构中的核心价值是快速定位跨服务调用链路的延迟、错误与瓶颈,以下是常见生产案例与排查方法。
案例一:某接口 P99 延迟突增,从 200ms 升至 5s
排查步骤:
1. Zipkin UI 搜索 serviceName=order-service,按 duration 降序
2. 发现 span "GET /api/inventory" 耗时 4.8s,占比 95%
3. 展开 span 查看 tags:http.status_code=200 但 db.statement 显示
4. 继续下钻 "SELECT * FROM inventory WHERE sku=?" 耗时 4.5s
5. 查看对应 service=inventory-service 的其他 Trace
6. 发现同一时间窗口存在慢 SQL + 连接池等待
根因:inventory-service 数据库缺失 sku 联合索引,全表扫描导致
解决:CREATE INDEX idx_inventory_sku ON inventory(sku)
验证:修复后 P99 下降至 180ms
案例二:下单接口随机报错 5%,错误源不明
排查步骤:
1. Zipkin UI 搜索 tags.error=true,serviceName=order-service
2. 错误 Trace 中定位到 span "POST payment-service" 抛异常
3. 查看 annotation:cs 存在但缺失 cr,duration 异常短
4. 推断为客户端超时(connectTimeout=500ms, readTimeout=2s)
5. 继续下钻:payment-service 在该时间窗口 CPU 100%
6. 查看 payment-service 自身 Trace,发现大量 Span "fegin-retry"
根因:payment-service 因 GC 频繁(Young GC 200ms+)处理变慢,
触发客户端超时与重试,雪崩效应
解决:
- 调整 JVM 堆内存(-Xmx 4g → 8g)
- payment-service 接口降级(非关键查询走缓存)
- 客户端禁用自动重试(feign.client.config.default.connectTimeout=2000,readTimeout=5000)
案例三:Zipkin UI 无法显示依赖图
现象:UI 页面打开后无响应,依赖图加载失败
排查:
1. 浏览器 Network 查看 /api/v2/dependencies 请求超时 30s
2. Zipkin Server 日志显示:QueryService 慢查询
3. 后端 MySQL 慢日志:SELECT COUNT(*) FROM zipkin_spans_dependencies 全表扫描
4. 存储后端存储了 90 天历史数据,依赖计算范围过大
根因:Zipkin 默认按 serviceName 全量计算依赖,数据膨胀导致超时
解决:
- 缩短依赖分析时间窗口(UI 限定 24h)
- MySQL 改 ES,利用 ES 聚合计算能力
- 配置数据保留策略:7d 后自动清理(zipkin.storage.strict-trace-id-ttl=true)
案例四:跨机房调用 Trace 断裂,部分服务无 Span
现象:调用链 order-service → payment-service(跨机房),
UI 上 payment-service Span 缺失
排查:
1. 抓取 order-service 出站请求 Header
2. 发现 X-B3-TraceId 存在,但 X-B3-SpanId 为空
3. 检查 order-service 网关(Spring Cloud Gateway)配置
4. 网关未开启 trace propagation,未透传 B3 Header
根因:Spring Cloud Gateway 与下游服务使用 Sleuth 时,需在 Gateway
Filter 中显式传递 Header
解决:
spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE sleuth: propagation: type: B3 factory-class-name: org.springframework.cloud.sleuth.brave.propagation.B3Propagation
**案例五:高 QPS 场景下应用线程阻塞**
现象:业务线程池排队,响应延迟上升 排查:
- 业务线程 Dump 显示大量线程阻塞在 Brave 的 httpClient.send
- Zipkin Server 端无响应,Collector 队列积压
- 监控显示 Zipkin Receiver QPS=0.3k,应用实际产生 5k Span/s
根因:同步 HTTP 上报,Collector 慢时阻塞业务线程 解决:
- 切换 sender.type: kafka
- 应用线程不再等待 Zipkin ACK
- 引入 OTel Collector 作为旁路,缓解 Zipkin 写入压力
**生产排查工具链:**
| 工具 | 用途 |
|------|------|
| **Zipkin UI** | Trace 时间线、Span 详情、依赖图 |
| **Zipkin API** | `GET /api/v2/trace/{traceId}` 编程化查询 |
| **TraceID 关联日志** | Sleuth 自动注入 MDC,ELK / Loki 可按 traceId 聚合 |
| **Metrics 联动** | Prometheus + Zipkin Tag serviceName 关联指标 |
| **火焰图** | SkyWalking / Jaeger 支持,与 Zipkin 数据互通 |
**核心原则:**
- 跨服务问题优先看 Trace,单服务问题优先看 Metrics。
- 关注 Span duration 占比,找到长尾 Span 即找到瓶颈。
- 生产环境开启 `tags.error=true` 与 `duration > 阈值` 告警。
- 始终为每个服务注入 `serviceName` + `host` + `env` 标签,便于多环境隔离。