微服務:分散式鏈路追蹤系統-jaeger
簡介
jaeger是一個比較有名的分散式鏈路追蹤系統,底層用golang實現,相容opentracing標準。
部署
我們用docker部署,整合整套環境,docker地址:https://hub.docker.com/r/jaegertracing/all-in-one
直接執行docker命令安裝:
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 9411:9411 \ jaegertracing/all-in-one:latest
執行完成後,用
命令:docker ps
看看執行起來沒,這裡看結果已經運行了:
訪問jaeger的web介面:
localhost:16686
如果你是遠端,這裡的localhost可以換成你的伺服器ip,或者你配置的域名。
簡單demo
先編寫一個初始化jaeger tracer的initJaeger方法:
此時我們要在reporter中配置jaeger Agent的ip與埠,以便將tracer的資訊釋出到agent中。配置LocalAgentHostPort引數為127.0.0.1:6381,6381介面是接受壓縮格式的thrift協議資料。如果是遠端這裡的 127.0.0.1 可以設定為你遠端ip地址。
取樣率暫且設定為1
func initJaeger(service string) (opentracing.Tracer, io.Closer) { cfg := &config.Configuration{ Sampler:&config.SamplerConfig{ Type: "const", Param:1, }, Reporter: &config.ReporterConfig{ LogSpans: true, LocalAgentHostPort: "127.0.0.1:6831", }, } tracer, closer, err := cfg.New(service, config.Logger(jaeger.StdLogger)) if err != nil { panic(fmt.Sprintf("Error: connot init Jaeger: %v\n", err)) } return tracer, closer }
然後我們在main函式中建立呼叫InitJaeger,並建立一個root span,呼叫兩個函式,分別表示呼叫兩個分散式服務。
我們用ContextWithSpan來建立一個新的ctx,將span的資訊與context關聯,傳到TestDemo中時,需要建立一個子span,父span是ctx中的span。
我們在TestDemo中呼叫StartSpanFromContext時,忽略了第二個引數,這是利用子span建立的新的context,當我們在TestDemo中再呼叫別的比如TestDemo2時,我們應該使用新的context,而不是傳入的ctx。
注意StartSpanFromContext會用到opentracing.SetGlobalTracer()來啟動新的span,所以在main函式中需要呼叫。
func TestDemo(req string, ctx context.Context) (reply string) {
// 1. 建立span
span, _ := opentracing.StartSpanFromContext(ctx, "span_testdemo")
defer func() {
// 4. 介面呼叫完,在tag中設定request和reply
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
//2. 模擬耗時
time.Sleep(time.Second/2)
//3. 返回reply
reply = "TestDemoReply"
return
}
// TestDemo2, 和上面TestDemo 邏輯程式碼一樣
func TestDemo2(req string, ctx context.Context) (reply string) {
span, _ := opentracing.StartSpanFromContext(ctx, "span_testdemo2")
defer func() {
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
time.Sleep(time.Second/2)
reply = "TestDemo2Reply"
return
}
func main() {
tracer, closer := initJaeger("jager-test-demo")
defer closer.Close()
opentracing.SetGlobalTracer(tracer)
span := tracer.StartSpan("span_root")
ctx := opentracing.ContextWithSpan(context.Background(), span)
r1 := TestDemo("Hello TestDemo", ctx)
r2 := TestDemo2("Hello TestDemo2", ctx)
fmt.Println(r1, r2)
span.Finish()
}
執行demo:
go run simple/main.go
執行提交的span資訊會打印出來:
21:57:30 debug logging disabled
21:57:30 Initializing logging reporter
21:57:30 debug logging disabled
Hello TestDemo
21:57:30 Reporting span 2163520004cced2a:4155a263b5147904:2163520004cced2a:1
Hello TestDemo2
21:57:31 Reporting span 2163520004cced2a:01928bf482621c17:2163520004cced2a:1
TestDemoReply TestDemo2Reply
21:57:31 Reporting span 2163520004cced2a:2163520004cced2a:0000000000000000:1
然後在去jaeger UI上重新整理檢視,會出現記錄:
可以發現有分層,時間耗時也明顯,介面先後呼叫也很清晰。
點選上面的 jager-test-demo 進去,可以看到下面的這種呼叫情況: