分布式追踪系统Jaeger
什么是 Jaeger?
Jaeger 是一个分布式追踪系统,主要用于监控和故障排查分布式系统中的微服务架构。它帮助开发者跟踪请求在多个微服务中的路径,发现系统瓶颈,并分析各个服务之间的延迟和依赖关系。Jaeger 最早由 Uber 开发,现在已经成为 CNCF (Cloud Native Computing Foundation) 的孵化项目之一。
Jaeger 的作用
- 分布式追踪:追踪请求从一个服务传递到另一个服务的路径,提供可视化的请求流。
- 性能监控:检测每个微服务的性能瓶颈,分析延迟,帮助优化系统。
- 故障排查:在复杂系统中快速定位错误发生的服务或阶段。
- 依赖关系分析:显示服务之间的调用链,帮助开发者理解系统架构。
Jaeger 的核心概念
-
Trace (追踪):
- 代表一个请求的整个生命周期,从进入系统的第一个服务到流经不同服务的整个过程。
- 每个
Trace
包含多个Span
。
-
Span (跨度):
Span
是Trace
中的一个单独的操作,例如一个 HTTP 请求、数据库查询、远程调用等。- 每个
Span
包括开始时间、持续时间、操作名称、标签、日志等信息。
-
Context (上下文):
- 上下文用于跨服务传递追踪信息,通常通过 HTTP headers 或 RPC 的元数据中传递。
-
Parent-Child 关系:
- 一个请求可能会经过多个微服务,每个服务的
Span
可以有父子关系,形成完整的调用链。
- 一个请求可能会经过多个微服务,每个服务的
Jaeger 的工作原理
Jaeger 使用了分布式追踪的四步流程:
-
Instrumentation (插桩):
- 在微服务中添加追踪代码,使服务在处理请求时能够生成
Span
并记录追踪数据。通过开源的追踪库(如 OpenTelemetry 或 OpenTracing)来插桩,自动生成追踪信息。
- 在微服务中添加追踪代码,使服务在处理请求时能够生成
-
Collection (收集):
- Jaeger 会将生成的
Span
数据发送到 Jaeger 后端系统。后端系统负责收集所有Span
并组装成完整的Trace
。
- Jaeger 会将生成的
-
Storage (存储):
- Jaeger 支持多种存储后端,包括 Elasticsearch、Cassandra、Kafka 等,用于持久化存储追踪数据。
-
Visualization (可视化):
- 用户可以通过 Jaeger UI 查看、分析追踪数据,定位性能瓶颈和错误位置。
Jaeger 的架构
Jaeger 典型架构包括以下组件:
- Agent:运行在每个服务节点上,负责将追踪数据发送到 Jaeger Collector。
- Collector:接收来自 Agent 的追踪数据并存储。
- Query Service:用户可以通过这个服务查询追踪数据,并通过 UI 展示。
- Storage Backend:存储追踪数据,支持 Cassandra、Elasticsearch 等。
如何学习使用 Jaeger
1. 安装 Jaeger
最简单的方式是通过 Docker 启动 Jaeger。首先,确保你已安装 Docker,然后运行以下命令来启动 Jaeger:
docker run -d --name jaeger \-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \-p 5775:5775/udp \-p 6831:6831/udp \-p 6832:6832/udp \-p 5778:5778 \-p 16686:16686 \-p 14268:14268 \-p 14250:14250 \-p 9411:9411 \jaegertracing/all-in-one:1.22
- 访问 Jaeger UI:http://localhost:16686
2. 在微服务中引入 Jaeger
通过 OpenTelemetry 或 OpenTracing 库在你的微服务代码中集成 Jaeger 追踪。下面是一个 Spring Boot 应用集成 Jaeger 的例子:
示例 1:使用 OpenTelemetry 集成 Jaeger
步骤 1:添加依赖
在 pom.xml
中添加 OpenTelemetry 和 Jaeger 的依赖:
<dependency><groupId>io.opentelemetry</groupId><artifactId>opentelemetry-exporter-jaeger</artifactId><version>1.5.0</version>
</dependency>
步骤 2:配置 Jaeger 导出器
在应用的 application.properties
中配置 Jaeger:
otel.exporter.jaeger.endpoint=http://localhost:14250
otel.exporter.jaeger.service.name=my-service
步骤 3:编写代码
在代码中初始化 OpenTelemetry 并生成 Span
:
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;@RestController
public class MyController {private static final Tracer tracer = GlobalOpenTelemetry.getTracer("example-tracer");@GetMapping("/hello")public String sayHello() {Span span = tracer.spanBuilder("sayHello-span").startSpan();span.addEvent("Saying hello");try {return "Hello, Jaeger!";} finally {span.end();}}
}
当你访问 /hello
端点时,Jaeger 会捕获到 sayHello-span
这个 Span
,并且你可以在 Jaeger UI 中查看到追踪信息。
3. 分布式追踪的实际使用场景
假设一个电子商务系统中有三个微服务:
- 订单服务:接收用户订单。
- 支付服务:处理用户支付。
- 发货服务:安排订单发货。
在系统中,一个请求可能从订单服务开始,依次传递到支付服务和发货服务。Jaeger 可以帮助我们跟踪这个请求在不同服务中的执行情况,生成以下调用链:
User -> [Order Service] -> [Payment Service] -> [Shipment Service]
通过 Jaeger,你可以在每个微服务中看到请求的执行时间和延迟情况,如果某个服务有性能瓶颈,可以快速定位。
示例 2:分布式追踪的实际使用
服务 A:订单服务
// OrderService.java
public void placeOrder(Order order) {Span span = tracer.spanBuilder("placeOrder").startSpan();try {// 处理订单paymentService.processPayment(order);shipmentService.scheduleShipment(order);} finally {span.end();}
}
服务 B:支付服务
// PaymentService.java
public void processPayment(Order order) {Span span = tracer.spanBuilder("processPayment").startSpan();try {// 模拟支付处理} finally {span.end();}
}
服务 C:发货服务
// ShipmentService.java
public void scheduleShipment(Order order) {Span span = tracer.spanBuilder("scheduleShipment").startSpan();try {// 模拟发货安排} finally {span.end();}
}
在 Jaeger UI 中,你可以看到一个完整的调用链,从订单服务到支付服务,再到发货服务。每个 Span
都会展示执行的时间,帮助你分析系统的性能和潜在的瓶颈。
结论
Jaeger 是强大的分布式追踪工具,帮助开发者跟踪和优化微服务架构中的请求流。通过简单的插桩,我们可以轻松获取每个请求的详细追踪数据,并在 Jaeger UI 中分析系统的性能和依赖关系。通过逐步学习如何集成 Jaeger 和使用分布式追踪,可以显著提高系统的可观测性和故障排查能力。