线上问题诊断实战:trace分析与现场快照回放 - 第4节
现象识别:分布式追踪缺失导致定位困难
当微服务架构中出现请求延迟激增、部分接口间歇性超时或错误率异常时,传统日志聚合(ELK)或指标监控(Prometheus)往往只能给出“哪里慢”的粗粒度提示,但无法精准还原一次请求在多个服务间的完整调用链。以下故障树总结了典型现象:
故障树:分布式调用链定位困难
根节点:无法定位故障服务 → 分解为三个分支:
① 无端到端请求上下文:
- 调用链断裂 → 无法判断慢调用发生在哪个服务
- 错误信息孤立 → 无法关联上游/下游错误
② 无精细化耗时分布:
- 总耗时已知但各服务耗时未知 → 无入口/出口span
③ 无拓扑依赖图:
- 服务间依赖关系不清晰 → 无法识别关键链路瓶颈
根节点:无法定位故障服务 → 分解为三个分支:
① 无端到端请求上下文:
- 调用链断裂 → 无法判断慢调用发生在哪个服务
- 错误信息孤立 → 无法关联上游/下游错误
② 无精细化耗时分布:
- 总耗时已知但各服务耗时未知 → 无入口/出口span
③ 无拓扑依赖图:
- 服务间依赖关系不清晰 → 无法识别关键链路瓶颈
上述现象表明:需要一套分布式追踪系统来采集、存储和可视化每次请求的span数据。本章将指导你完成Jaeger/Zipkin/SkyWalking的选型、Agent部署、采样策略配置及存储后端搭建。
数据采集:选型与部署
1. 选型对比
| 特性 | Jaeger | Zipkin | SkyWalking |
|---|---|---|---|
| 协议 | OpenTelemetry / Jaeger thrift | Zipkin JSON / OpenTelemetry | gRPC / HTTP (SkyWalking原生协议) |
| 侵入性 | 低,支持自动instrumentation(Java/Go/Python) | 中,需手动或通过Sleuth/Zipkin客户端 | 低,Java Agent自动探针,其他语言需SDK |
| 存储后端 | Elasticsearch / Cassandra / Badger | Elasticsearch / Cassandra / MySQL | Elasticsearch / H2 / MySQL / TiDB |
| 采样策略 | 基于头(head-based)概率/速率/远程配置 | 基于头概率/速率,无远程配置 | 基于头采样+自适应采样+动态配置 |
| 社区活跃度 | 高,CNCF毕业项目 | 中,CNCF孵化项目 | 高,Apache顶级项目 |
| 典型场景 | 云原生、K8s环境、需要OpenTelemetry集成 | 传统Java微服务、Spring Cloud生态 | APM全套(指标+追踪+拓扑)+ Java系为主 |
选型判断规则:
- 如果已有OpenTelemetry Collector,优先选择Jaeger;
- 如果是纯Java Spring Boot项目并希望零代码插入,选择SkyWalking Java Agent;
- 如果团队熟悉Elasticsearch且对资源敏感,Zipkin + ES是最轻量方案。
2. Agent配置(以Jaeger为例)
Jaeger Agent是sidecar模式,每个节点上运行,负责接收应用发送的span并批量转发到Collector。以下为通过环境变量配置Java应用发送trace到Agent的示例:
# Java应用启动参数(使用Jaeger Java Client)
java -javaagent:/path/to/jaeger-agent.jar \
-DJAEGER_AGENT_HOST=jaeger-agent.default.svc.cluster.local \
-DJAEGER_AGENT_PORT=6831 \
-DJAEGER_SERVICE_NAME=order-service \
-DJAEGER_SAMPLER_TYPE=probabilistic \
-DJAEGER_SAMPLER_PARAM=0.1 \
-jar order-service.jar
对于使用OpenTelemetry SDK的应用,Agent配置更简洁:
# OTel collector作为gateway
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
export OTEL_SERVICE_NAME="payment-service"
export OTEL_TRACES_SAMPLER="traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.1"
3. 采样策略配置
采样策略直接影响数据量、存储成本和问题排查覆盖率。常用策略及配置如下:
| 策略 | 配置示例(Jaeger) | 适用场景 |
|---|---|---|
| 概率采样 | JAEGER_SAMPLER_TYPE=probabilisticJAEGER_SAMPLER_PARAM=0.05 | 高流量生产环境,5%采样降低存储压力 |
| 速率限制采样 | JAEGER_SAMPLER_TYPE=ratelimitingJAEGER_SAMPLER_PARAM=10 | 每秒最多采样10条trace,适合对整体QPS有感知的场景 |
| 远程采样(自适应) | 通过Jaeger Collector动态下发采样策略 | 需要根据服务负载自动调整采样率,避免热点服务采样不足 |
| 基于头的优先级采样 | 设置自定义采样头(如X-Debug-Sample: 1) | 调试阶段强制全量采样,不影响生产默认策略 |
采样策略决策表(基于问题排查场景):
- 当需要排查稀有问题(如偶发超时)时,应提高采样率至20%-50%,或开启远程采样动态上调;
- 对核心交易链路,建议使用“固定概率+远程覆盖”策略,确保兜底;
- 避免在低流量服务上开启全量采样(数据量小但浪费存储)。
4. 存储后端配置(Elasticsearch示例)
存储后端决定了trace的持久化能力和查询性能。以下为Jaeger搭配Elasticsearch的docker-compose配置核心片段:
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.21
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
jaeger-collector:
image: jaegertracing/jaeger-collector:1.57
command: ["--es.server-urls=http://elasticsearch:9200",
"--es.trace-storage.span-store.type=elasticsearch",
"--collector.zipkin.host-port=:9411"]
ports:
- "14250:14250"
- "14269:14269"
jaeger-query:
image: jaegertracing/jaeger-query:1.57
command: ["--es.server-urls=http://elasticsearch:9200",
"--span-storage.type=elasticsearch"]
ports:
- "16686:16686"
jaeger-agent:
image: jaegertracing/jaeger-agent:1.57
command: ["--reporter.grpc.host-port=jaeger-collector:14250"]
ports:
- "6831:6831/udp"
- "6832:6832/udp"
存储规划检查表:
- 确定每天trace数据量(可通过
span数 × 平均span大小 × 采样率估算); - 预留ES索引模板生命周期管理(ILM),例如7天后自动删除或冷热迁移;
- 监控ES磁盘使用率和搜索延迟,避免成为瓶颈。
原因定位:选型不当或配置错误导致数据缺失
即使搭建完成,也可能出现数据采集不全、Agent无法上报、采样策略过高等问题。以下为典型排查流程:
常见问题1:应用已发送span,但查询不到trace
排查步骤:
1. 检查Agent日志:
2. 使用
3. 在Collector侧查看接收指标(
4. 若使用OpenTelemetry,检查Collector配置中是否启用了batch processor或memory_limiter导致数据被丢弃。
排查步骤:
1. 检查Agent日志:
docker logs jaeger-agent 或 kubectl logs jaeger-agent-xxx,确认是否有“no connection to collector”错误;2. 使用
netstat或tcpdump验证端口6831/14250是否可达;3. 在Collector侧查看接收指标(
/metrics),确认received_spans计数器是否增长;4. 若使用OpenTelemetry,检查Collector配置中是否启用了batch processor或memory_limiter导致数据被丢弃。
常见问题2:采样率设置过高导致存储写满
现象:ES集群持续red状态,jaeger-query查询超时。
修复动作:立即降低采样参数(如从0.5降到0.05),并增加Index Lifecycle Policy自动清理过期索引。
现象:ES集群持续red状态,jaeger-query查询超时。
修复动作:立即降低采样参数(如从0.5降到0.05),并增加Index Lifecycle Policy自动清理过期索引。
修复动作:动态调整采样与存储优化
基于“原因定位”中的判断,修复动作分为三类:
- Agent连接修复:确保Agent与Collector之间的网络策略(K8s NetworkPolicy或防火墙)开放gRPC端口;使用
JAEGER_REPORTER_LOG_SPANS=true临时观察span是否发送。 - 采样策略动态调整:Jaeger支持通过Collector的
sampling.strategies-file或API动态下发。例如创建一个JSON文件并挂载到Collector:
{
"service_strategies": [
{
"service": "order-service",
"type": "probabilistic",
"param": 0.2
},
{
"service": "payment-service",
"type": "probabilistic",
"param": 0.5
}
],
"default_strategy": {
"type": "probabilistic",
"param": 0.05
}
}
之后通过curl触发重载:
curl -X POST http://jaeger-collector:14269/sampling
- 存储优化:为Elasticsearch配置ILM模板,设置7天滚动;调整ES分片数(建议5-10分片/索引);使用SSD或冷热分离。
复测:验证trace数据完整收集
完成修复后,执行以下复测步骤:
- 对被测服务发起10次HTTP请求(其中一次带有自定义trace ID头,如
X-B3-TraceId: abc123); - 在Jaeger UI中搜索服务名,确认span数匹配预期(采样率×请求数);
- 检查trace的完整调用链深度(包括调用外部服务、数据库等);
- 查看ES索引
jaeger-span-*的文档计数,确认数据持久化正常; - 使用
curl jaeger-query:16686/api/traces?service=order-service获取API响应。
预防:建立追踪系统健康基线
为防止追踪系统自身成为故障点,制定以下预防规则:
- 监控Agent存活:每个Pod内Agent容器必须设置
livenessProbe(例如检查:6831端口); - 采样率限制:设置全局最大每秒span数(Collector端限流),避免突发流量打爆Agent内存;
- 存储容量预警:ES磁盘利用率超过80%时触发告警,并自动降低采样率(通过外部控制脚本或K8s Operator);
- 定期演练:每季度执行一次“trace中断”混沌实验,断开Agent与Collector连接,验证业务是否能降级关闭trace发送(使用
JAEGER_DISABLED=true)。
生产建议:始终为追踪系统预留独立资源池,不要与业务应用混部;对存储后端启用跨AZ冗余,避免单点故障导致trace数据丢失。