go micro 鏈路追蹤

本片介紹go micro中使用jaeger做爲鏈路追蹤的使用html

jaeger相關知識請見官方文檔,這裏使用docker啓動gaeger,做爲測試使用git

啓動jaegergithub

docker run -d -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one:latestweb

訪問地址http://localhost:16686docker

go micro版本2.x,和1.x有些許不一樣segmentfault

樣例代碼使用examples/greeter中代碼修改
srv/mian.goapp

// Package main
package main

import (
    "context"
    "io"
    "time"

    hello "github.com/micro/examples/greeter/srv/proto/hello"
    "github.com/micro/go-micro/v2"
    "github.com/micro/go-micro/v2/util/log"

    wrapperTrace "github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    jaegercfg "github.com/uber/jaeger-client-go/config"
)

type Say struct{}

func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
    log.Log("Received Say.Hello request")
    rsp.Msg = "Hello " + req.Name
    return nil
}

func main() {
    t, io, err := NewTracer("tracer-srv", "127.0.0.1:6831")
    if err != nil {
        log.Fatal(err)
    }
    defer io.Close()
    opentracing.SetGlobalTracer(t)
    service := micro.NewService(
        micro.Name("go.micro.srv.greeter"),
        micro.WrapHandler(wrapperTrace.NewHandlerWrapper(opentracing.GlobalTracer())),
    )

    // optionally setup command line usage
    service.Init()

    // Register Handlers
    hello.RegisterSayHandler(service.Server(), new(Say))

    // Run server
    if err := service.Run(); err != nil {
        log.Fatal(err)
    }
}

// NewTracer 建立一個jaeger Tracer
func NewTracer(servicename string, addr string) (opentracing.Tracer, io.Closer, error) {
    cfg := jaegercfg.Configuration{
        ServiceName: servicename,
        Sampler: &jaegercfg.SamplerConfig{
            Type:  jaeger.SamplerTypeConst,
            Param: 1,
        },
        Reporter: &jaegercfg.ReporterConfig{
            LogSpans:            true,
            BufferFlushInterval: 1 * time.Second,
        },
    }

    sender, err := jaeger.NewUDPTransport(addr, 0)
    if err != nil {
        return nil, nil, err
    }

    reporter := jaeger.NewRemoteReporter(sender)
    // Initialize tracer with a logger and a metrics factory
    tracer, closer, err := cfg.NewTracer(
        jaegercfg.Reporter(reporter),
    )

    return tracer, closer, err
}

這裏封裝了`NewTracer()`建立一個jaeger Tracer分佈式

在main()中opentracing.SetGlobalTracer(t)設置給opentracing工具

micro的wrapper有4種:測試

  1. WrapHandler() server中間件
  2. WrapCall() call中間件
  3. WrapClient() client中間件
  4. WrapSubscriber() 訂閱中間件

server端咱們使用micro.WrapHandler()

經過micro plugins自帶的opentracing插件設置下

wrapperTrace.NewHandlerWrapper(opentracing.GlobalTracer())

cli/mian.go

package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "time"

    hello "github.com/micro/examples/greeter/srv/proto/hello"
    "github.com/micro/go-micro/v2"

    wrapperTrace "github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    jaegercfg "github.com/uber/jaeger-client-go/config"
)

func main() {
    t, io, err := NewTracer("tracer-cli", "127.0.0.1:6831")
    if err != nil {
        log.Fatal(err)
    }
    defer io.Close()
    opentracing.SetGlobalTracer(t)
    // ctx, span, err := wrapperTrace.StartSpanFromContext(context.Background(), opentracing.GlobalTracer(), "root")

    // create a new service
    service := micro.NewService(
        micro.WrapClient(wrapperTrace.NewClientWrapper(opentracing.GlobalTracer())),
    )

    // parse command line flags
    service.Init()

    // Use the generated client stub
    cl := hello.NewSayService("go.micro.srv.greeter", service.Client())

    // Make request
    rsp, err := cl.Hello(context.Background(), &hello.Request{
        Name: "John",
    })
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(rsp.Msg)
}

// NewTracer 建立一個jaeger Tracer
func NewTracer(servicename string, addr string) (opentracing.Tracer, io.Closer, error) {
    cfg := jaegercfg.Configuration{
        ServiceName: servicename,
        Sampler: &jaegercfg.SamplerConfig{
            Type:  jaeger.SamplerTypeConst,
            Param: 1,
        },
        Reporter: &jaegercfg.ReporterConfig{
            LogSpans:            true,
            BufferFlushInterval: 1 * time.Second,
        },
    }

    sender, err := jaeger.NewUDPTransport(addr, 0)
    if err != nil {
        return nil, nil, err
    }

    reporter := jaeger.NewRemoteReporter(sender)
    // Initialize tracer with a logger and a metrics factory
    tracer, closer, err := cfg.NewTracer(
        jaegercfg.Reporter(reporter),
    )

    return tracer, closer, err
}

client端增長的代碼和server基本一致,

只是micro.NewService()中使用的是中間件是micro.WrapClient()

同時參數相應的變爲wrapperTrace.NewClientWrapper(opentracing.GlobalTracer())

運行起來

go run srv/main.go
go run cli/main.go

刷新http://localhost:16686/便可看到

image
image
總結:

  1. go micro 在整個請求週期中都會帶着ctx,放入header中,詳情請見【micro server分析】,鏈路追蹤的原理就是在header中拿到追蹤信息,存入分析工具並解析,再展示到頁面。
  2. 鏈路追蹤不只能夠用於追蹤整個請求週期,還可自定義追蹤某幾行代碼,具體請見官方文檔

參考【go-micro實踐】jaeger分佈式鏈路追蹤

go micro 分析系列文章
go micro server 啓動分析
go micro client
go micro broker
go micro cmd
go micro config
go micro store
go micro registry
go micro router
go micro runtime
go micro transport
go micro web
go micro registry 插件consul
go micro plugin
go micro jwt 網關鑑權
go micro 鏈路追蹤
go micro 熔斷與限流
go micro wrapper 中間件
go micro metrics 接入Prometheus、Grafana

相關文章
相關標籤/搜索