1. 简介
Opentracing是一个用于分布式系统中追踪和监控请求的规范和 API,它旨在提供一个标准的接口,使得开发者能够在不同的追踪系统之间无缝切换和集成。OpenTracing
的目标是使得追踪信息能够跨越多个组件和服务,以便全面了解系统性能,并且方便地集成到各种追踪系统中。
Opentracing的主要特点和组成部分如下:
- Vendor-Neutral(厂商中立):
OpenTracing
是一个厂商中立的规范,不与特定的追踪系统绑定。这意味着你可以选择使用任何符合OpenTracing
规范的追踪实现,而不必担心锁定到特定的实现。 - Instrumentation API(仪器化 API):
OpenTracing
提供了一组 API,用于在代码中插入追踪信息,以便追踪请求在分布式系统中的传播。这些 API 允许开发者在关键点注入追踪代码,记录请求的起始和结束时间,以及其他相关信息。 - Span 和 Trace(跨度和追踪): 在
OpenTracing
中,Span
表示请求的一个特定操作,而Trace
则是一系列Span
组成的链,表示整个请求的生命周期。通过这种方式,可以构建起对请求在分布式系统中的完整追踪视图。 - 支持多语言:
OpenTracing
支持多种编程语言,包括但不限于 Java、Go、Python、JavaScript 等。这样,你可以在不同的组件和服务中使用相同的OpenTracing
API,以实现一致的追踪。 - 社区驱动:
OpenTracing
是一个开源项目,由一个活跃的社区进行维护和推动。这使得它能够持续发展,并适应不断变化的分布式系统和追踪技术。
2. 原理
Opentracing的原理涉及到分布式追踪的基本概念,包括 Span
、Trace
、Context
等,以及在应用程序中如何使用 OpenTracing API
进行仪器化(instrumentation),其原理是通过在应用程序中插入仪器化代码,记录 Span
和传播 Context
,从而构建起跨服务的请求追踪链。这使得开发者能够更好地理解分布式系统中请求的行为和性能。
- Span(跨度):Span 是 OpenTracing 中的基本工作单元,它代表一个请求的特定操作或事件。Span 包含了一些元数据,如操作的名称、开始和结束时间等。在一个分布式系统中,Span 可能在多个服务之间传播,构成整个请求的跟踪链。每个服务的处理都会创建和记录属于自己的 Span。
- Trace(追踪):Trace 是一系列相关的 Span 组成的链,表示整个请求的生命周期。Trace 提供了对请求在分布式系统中传播的完整视图。
Trace 的起始点通常是一个入口服务接收到请求,然后创建一个起始的 Span。每个服务的处理都会创建新的 Span,并在 Trace 链中连接起来。 - Context(上下文):Context 是在请求处理过程中传递的信息,它包含了请求的元数据。在 OpenTracing 中,Context 通常通过 Span 进行传递。在分布式系统中,Context 可能被传递给其他服务,以便它们能够继续相同的 Trace。
- TracerProvider(追踪器提供者):TracerProvider 是负责创建和管理 Tracer 实例的组件。每个服务通常有一个 TracerProvider,用于创建服务内部的 Tracer 实例。Tracer 负责创建和管理 Span,记录追踪信息,并将信息发送到后端的追踪系统。
3. 使用示例
这里以golang为例,展示了基于opentracing的使用示例。
package main
import (
"bufio"
"os"
"time"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
jaegercfg "github.com/uber/jaeger-client-go/config"
jaegerlog "github.com/uber/jaeger-client-go/log"
)
func main() {
var cfg = jaegercfg.Configuration{
ServiceName: "client test", // 对其发起请求的的调用链,叫什么服务
Sampler: &jaegercfg.SamplerConfig{
Type: jaeger.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegercfg.ReporterConfig{
LogSpans: true,
CollectorEndpoint: "127.0.0.1:14268/api/traces",
},
}
jLogger := jaegerlog.StdLogger
tracer, closer, _ := cfg.NewTracer(
jaegercfg.Logger(jLogger),
)
// 创建第一个 span A
parentSpan := tracer.StartSpan("A")
time.Sleep(time.Second * 1)
// 调用其它服务
B(tracer, parentSpan)
// 结束 A
parentSpan.Finish()
// 结束当前 tracer
closer.Close()
reader := bufio.NewReader(os.Stdin)
_, _ = reader.ReadByte()
}
func B(tracer opentracing.Tracer, parentSpan opentracing.Span) {
// 继承上下文关系,创建子 span
childSpan := tracer.StartSpan(
"B",
opentracing.ChildOf(parentSpan.Context()),
)
time.Sleep(time.Second * 2)
defer childSpan.Finish()
}