golang微服務實踐:分布式鏈路追蹤系統-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 進去,可以看到下面的這種調用情況:

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM