前言
- 在微服务开发中,经常会有一个接口中先调用A服务再调用B服务,甚至C、D、E服务等多服务调用的情况,这时候如果某个服务出现了问题,我们不知道在哪里断了,或者只能依靠多点日志排查,比较麻烦。这时候链路追踪的优势就出来了。
- 正常的链路追踪我了解到的Zipkin和Jaeger比较多,我使用的是Jaeger
先实践看下效果再梳理下jaeger的知识点
实践
- 注册全局的jaeger
go
func InitTracing() {
cfg := jaegerConfig.Configuration{
ServiceName: "main-client",//服务名字
Sampler: &jaegerConfig.SamplerConfig{
Type: jaeger.SamplerTypeRemote,
Param: 1,//所有的服务都被采样
},
Reporter: &jaegerConfig.ReporterConfig{
LocalAgentHostPort: "127.0.0.1:6831",
LogSpans: true,
BufferFlushInterval: 5 * time.Second,// 5s提交一次traces
},
}
nativeTracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger))
if err != nil {
logger.Errorf("unable to create jaeger tracer err : %+v\n", err)
return
}
// defer closer.Close()
opentracing.SetGlobalTracer(nativeTracer) //设置全局tracer
}
- 注册完之后就是全局的jaeger
- 可以在调用微服务之前添加链路
go
nativeTrace := opentracing.GlobalTracer() //获取全局的tracer
span := nativeTrace.StartSpan("mainSpan") //span服务名称
defer span.Finish() //延迟释放
ctx := opentracing.ContextWithSpan(context.Background(), span) //将信息载入上下文
resp, err := GrpcServer.Create(ctx, &profileRequest) //将载入信息的上下文传入
// 可以在多处微服务调用的都加上span
spanA := nativeTrace.StartSpan("artistInfo")
- 可以在jaegerUI里查看链路信息
- 完整的链路数据
- 哪个链路断了可以看出来
- 可以添加tag 和 log,方便我们排查
go
span.SetTag("UpdateStorage", span.Tracer())
span.LogFields(log.String("event", "UpdateStorage"),// 添加log
log.String("value", in.ArtworkUuid),
)
span.SetTag("storage-update-storage", storageRequest.ArtworkUuid) //设置tag
- 真实环境下链路数据会不停的刷新,我们可以结合tag进行搜索
- tagName:tagValue 或者等于号也可以
jaeger知识梳理
jaeger介绍
- 官方文档,官方文档还有go和java的jaeger初始化代码示例
Jaeger
是一个开源的,用于追踪分布式服务间事务的软件。它主要被用来监控和故障排除复杂的微服务环境。Jaeger
使用分布式跟踪来了解不同微服务的请求路径。Jaeger
提供了一个系统用于收集、存储、查询和可视化在微服务间完成一个特定事务时产生的请求数据。这可以帮助开发人员更好地理解他们的软件实现,使用更少的时间寻找和解决问题。- jaeger的主要功能
- 分布式上下文传播:Jaeger 在服务间传播请求上下文,以实现事务跟踪。
- 存储和检索:Jaeger 收集和存储请求数据,然后提供了一个接口用于查询这些数据。
- 可视化:Jaeger 提供了一个 Web 界面,用于显示服务间交互的时间序列视图,以助于性能分析和故障排除。
jaeger的知识单元
span基础
-
span 是链路追踪中基本组成要素、一个span表示一个独立的工作单元,比如标识一次函数调用,一次Http请求,span会记录如下基本要素
-
服务名称 operation name
-
服务的开始和结束时间
-
kv形式的tags
-
kv形式的logs
-
SpanContext
-
references:该span都一个或多个span的引用
-
-
Tags
-
以kv键值对的形式保存用户自定义标签,主要用于链路追踪结果的查询过滤
-
span的tag仅对自己可见,不会随着spancontext传递给后续span
-
可以在jaeger上进行tag过滤 storage-update-storage=69ca0063-fdf8-49d5-8161-80bc2a19af3411,逗号分隔多条件过滤
-
-
Logs
- logs和tags类似,也是kv键值对形式,与tags不同,logs会记录logs的时间,因为logs主要用户记录某些事情发生的时间,logs与key值必须是字符串,value的类型没有限制
SpanContext
- SpanContext 携带着一些跨服通信的数据,主要包含
- 足够在系统中标识该span的信息,比如:span_id,trace_id
- Baggage Items 为整条追踪保存跨服务(跨进程)的kv格式的用户自定义数据
- Baggage Items 与tag类似,也是kv键值对,与tags不同的是
- kv 都只能是字符串
- baggage items 不仅当前span可见,其会随着span contenxt 传给给后续所有的子span,使用baggage items 要注意网络性能和CPU开销
Reference
- opentracing 定义了两种引用关系ChildOf 和 FollowForm
- ChildOf :父span的执行依赖子span的执行结果是,此时子span对父span的引用关系是ChildOf,比如对于一次RPC调用,服务端的span 子 span与客户端的span(父span)是ChildOf关系
- FollowFrom:父span的执行不依赖子span的执行结果,此时子span对父span的引用关系是FollowFrom,FollowFrom常用于异步调用的表示,例如消息队列中的consumer span 与producer span 之间的关系
Trace
- trace表示一次完整的链路追踪,trace由一个或多个span组成,下入表示了一个由4个span组成的trace
Inject/Extract
- 为了实现分布式系统中的链路追踪。OpenTracing 提供了 inject、Extract用于- 在请求中注入SpanContext或者从请求中提取出SpanContext
- 客户端通过Inject将SpanContext注入在载体中,随着请求一起发送到服务端
- 服务端则通过Extract将SpanContext提取出来,进行后续处理