Jaeger项目地址
OpenTracing-Golang项目地址
这个Jaeger是Uber的分布式追踪系统,可以说是调用链追踪吧,这些调用链追踪系统都是参照Dapper。这里有一个中文版翻译,可以看看:
Dapper 翻译
按照我的理解,应该就是给一个调用链一个全局ID,无论是走RPC调用还是直接Restful HTTP调用,都需要带着这个ID,这样就可以形成一个链,根据这个ID就可以把Span的信息全部串起来了。
这里盗张图,Jaeger官网:
刚开始看到这张图我也是懵逼的,怎么会有这么多东西,这几个怎么串起来的,跟OpenTracing又是啥关系,怎么把Data Store换成ES或者kafka。我也是慢慢看文档,然后试出来的,后面的会给一个具体流程,希望有帮助。
下面看下各个组件
这两个是连在一块儿的,这两个东西都是插在我们业务代码里面的,就是要在我们的代码里面加入OpenTracing的代码。OpenTracing提供了很多语言的API,详细的可以看看上面的GitHub。对于Golang来说,主要的就是下面几个API:
opentracing.SetGlobalTracer() //设置全局的tracer
opentracing.StartSpan() //开始一个span
opentracing.GlobalTracer().Inject() //把span信息注入到http请求里面
opentracing.GlobalTracer().Extract() //从http请求里面解析出上一个服务的span信息
可以看到上面的SetGlobalTracer是可以设置成其他的tracer的,比如zipkin其他的,如果需要改动tracer的话,就只需要改这个参数即可,不需要改动其他插入的代码。
Jaeger的客户端就相当于上面的tracer,在代码里面SetGlobalTracer的时候,参数传的就是Jaeger-client New出来的一个实例。既然是客户端,那么服务端是什么呢?服务端是Jaeger-agent。
这个是Jaeger的服务端,客户端会把Span的信息通过Jaeger.Thrift UDP传给Jaeger-agent,再由Jaeger-agent把这些span的信息传给Jaeger-collector。
为啥不直接把信息传到collector?从上面的图我猜测,collector应该是对agent有采样率的限制,在代码里面可以看到相关的设置。
负责把Jaeger-agent传过来的数据写入队列,并且保存到设定的存储介质里面[内存,ES,kafka…]
这个是负责从存储介质里面读取调用链信息的,并且这个query自带UI,可以在UI里面看到相关的调用链。
#!/bin/bash
wget es.tar.gz
tar -xvzf es.tar.gz
wget jaeger.tar.gz
tar -xvzf jaeger.tar.gz
cd es/bin && ./elasticsearch
cd jaeger/bin
export SPAN_STORAGE_TYPE=elasticsearch
./jaeger-collector --es.server-urls=http://192.168.26.83:9200
./jaeger-agent --reporter.tchannel.host-port=192.168.26.83:14267
./jaeger-query --es.server-urls http://192.168.26.83:9200
上面的export是必须的,千万别忘了。第五点也是重点!!!
上面的export是必须的,千万别忘了。第五点也是重点!!!
上面的export是必须的,千万别忘了。第五点也是重点!!!
如果不出意外的话,lsof -i的话可以看到类似于下面的这张图:
从上面可以看到:
① 黄色框里面的内容:agent和collector建立了连接,14267这个端口的作用在文档里面有说:
14267- - - TChannel - - -used by jaeger-agent to send spans in jaeger.thrift format
是agent发送span给collector的通道
② 蓝色框里面的内容:分别是query组件和collector组件跟ES建立的连接,collector负责往ES里面写,query负责从ES里面读。
③ 红色框是代码里面初始化Jaeger-client之后,client跟agent建立起的连接,6831这个接口在文档里面有说:
6831- - - UDP- - -accept jaeger.thrift over compact thrift protocol
是client发送信息给agent的通道,通过thrift协议
现在应该就通了:
client生成的span信息通过6831发送到agent,agent再根据采样率来筛选记录,再通过14267传给collector,collector再通过9200往ES里面写,query通过9200从ES里面读并提供UI。
最关键的就是Jaeger的初始化和OpenTracing的初始化:
//这个是初始化jaeger-client的配置,包括采样率和报告方式
cfg = jaegercfg.Configuration {
Sampler : &jaegercfg.SamplerConfig {
Type : "const",
Param : 1,
},
Reporter : &jaegercfg.ReporterConfig {
LogSpans : true,
},
}
// 这个是创建jaeger-client,现在我们就可以得到一个jaeger tracer了
tracer, closer, err := cfg.New(
"elasticSearch-Jaeger",
jaegercfg.Logger(jLogger),
jaegercfg.Metrics(jMetricsFactory),
)
//把OpenTracing的tracer设置成jaeger
opentracing.SetGlobalTracer(tracer)
// 开始一个Span
sp := opentracing.StartSpan("get_function")
// 创建子Span
sp := opentracing.StartSpan(
"one_function",
opentracing.ChildOf(parentSpan.Context()))
// 结束span记录
sp.Finish()
// 追加span 日志
sp.LogFields(
openlog.String("Function_Name", logString),
openlog.Int("Wating millis", 1000))
// 远程调用之前需要往请求里面注入当前的span信息:
opentracing.GlobalTracer().Inject(
sp.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(httpReq.Header))
// 远程调用响应时需要解析调用的span:
wireContext, err := opentracing.GlobalTracer().Extract(
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(r.Header))
sp = opentracing.StartSpan(
"second_service_function",
ext.RPCServerOption(wireContext))
我们使用PostMan发送请求之后,可以在Jaeger-UI里面看到相关的调用链:
跟代码里面的sleep的时间是对应的上的,并且层级关系也很清楚。
如果你也启动了Kibana的话,那么在Kibana的页面也可以看到Span的相关信息:
GitHub
这个只是Demo,并且采样率设置的是每一条记录都需要收集,具体的参数还需要查阅文档或者代码,这边博客的目的在于了解并且开始熟悉OpenTracing,之前我对于这个OpenTracing的概念是模糊的,而且加上了Jaeger之后我更懵逼了, 通过一个星期的自学,我自己走了一遍流程,发现还是可以按照文档做出来一个Demo的,还是算比较欣慰吧,希望能帮助到大家。