线上问题诊断实战:trace分析与现场快照回放 - 第4节

现象识别:分布式追踪缺失导致定位困难

当微服务架构中出现请求延迟激增、部分接口间歇性超时或错误率异常时,传统日志聚合(ELK)或指标监控(Prometheus)往往只能给出“哪里慢”的粗粒度提示,但无法精准还原一次请求在多个服务间的完整调用链。以下故障树总结了典型现象:

故障树:分布式调用链定位困难
根节点:无法定位故障服务 → 分解为三个分支:
① 无端到端请求上下文:
- 调用链断裂 → 无法判断慢调用发生在哪个服务
- 错误信息孤立 → 无法关联上游/下游错误
② 无精细化耗时分布:
- 总耗时已知但各服务耗时未知 → 无入口/出口span
③ 无拓扑依赖图:
- 服务间依赖关系不清晰 → 无法识别关键链路瓶颈

上述现象表明:需要一套分布式追踪系统来采集、存储和可视化每次请求的span数据。本章将指导你完成Jaeger/Zipkin/SkyWalking的选型、Agent部署、采样策略配置及存储后端搭建。

数据采集:选型与部署

1. 选型对比

特性JaegerZipkinSkyWalking
协议OpenTelemetry / Jaeger thriftZipkin JSON / OpenTelemetrygRPC / HTTP (SkyWalking原生协议)
侵入性低,支持自动instrumentation(Java/Go/Python)中,需手动或通过Sleuth/Zipkin客户端低,Java Agent自动探针,其他语言需SDK
存储后端Elasticsearch / Cassandra / BadgerElasticsearch / Cassandra / MySQLElasticsearch / 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=probabilistic
JAEGER_SAMPLER_PARAM=0.05
高流量生产环境,5%采样降低存储压力
速率限制采样JAEGER_SAMPLER_TYPE=ratelimiting
JAEGER_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"

存储规划检查表:

  1. 确定每天trace数据量(可通过span数 × 平均span大小 × 采样率估算);
  2. 预留ES索引模板生命周期管理(ILM),例如7天后自动删除或冷热迁移;
  3. 监控ES磁盘使用率和搜索延迟,避免成为瓶颈。

原因定位:选型不当或配置错误导致数据缺失

即使搭建完成,也可能出现数据采集不全、Agent无法上报、采样策略过高等问题。以下为典型排查流程:

常见问题1:应用已发送span,但查询不到trace
排查步骤:
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自动清理过期索引。

修复动作:动态调整采样与存储优化

基于“原因定位”中的判断,修复动作分为三类:

  • 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数据完整收集

完成修复后,执行以下复测步骤:

  1. 对被测服务发起10次HTTP请求(其中一次带有自定义trace ID头,如X-B3-TraceId: abc123);
  2. 在Jaeger UI中搜索服务名,确认span数匹配预期(采样率×请求数);
  3. 检查trace的完整调用链深度(包括调用外部服务、数据库等);
  4. 查看ES索引jaeger-span-*的文档计数,确认数据持久化正常;
  5. 使用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数据丢失。
分布式追踪系统选型与数据流 分布式追踪系统选型决策与数据流 微服务应用 Jaeger Agent / OTel Collector 配置采样策略(概率/速率/远程) 选型? Jaeger Zipkin SkyWalking Elasticsearch Cassandra / MySQL Elasticsearch / H2 Jaeger Query / UI ⚠ 选型关键准则 • Jaeger + OTel适合多云原生环境,支持gRPC/HTTP • SkyWalking适合Java/APM一体化,零侵入;Zipkin轻量但需手动埋点