Jaeger 全鏈路實戰

鏈路追蹤

當今互聯網正在往微服務化發展,複雜的模塊,繁瑣的層級調度。數不清的機器,看不盡的日誌,各樣的語言開發,形形色色的團隊。排查問題難上加難,這就導致了鏈路追蹤的出現。今天來分享下實戰

預期收益

1、一鍵查詢上下游業務
2、鏈路耗時實時性反饋

服務安裝啓動

首先去https://www.jaegertracing.io/download/ 下載對應操作系統鏡像。
本地測試的話 建議直接運行./jaeger-all-in-one
如果是線上環境建議分開操作

Agent

我先簡單說下 Agent是幹什麼的吧,它主要負責收集程序、監聽UDP端口 將數據批量發給collector. 獨立部署,方便解耦。那麼獨立部署自然需要啓動進程,下邊我是以ES數據落地爲準 啓動的服務。

export SPAN_STORAGE_TYPE=elasticsearch
nohup  ./jaeger-agent  --collector.host-port=127.0.0.1:14267 --discovery.min-peers=1 --log-level=debug > agent.log 2>&1 &

Collector

接收agent 批量發來的數據,將數據落地到我們選擇的存儲裏面,Collector 本身是無狀態的。我們可以運行多個collector.

export SPAN_STORAGE_TYPE=elasticsearch
nohup ./jaeger-collector --es.server-urls=http://127.0.0.1:9200 --es.index-prefix=push --es.username=* --es.password=*  --log-level=debug > collector.log  2>&1 & 

要注意ES一般都是有auth認證的。需要填寫對 才能上報成功

UI展示

顧名思義,數據我們既然存儲落地了,這就是個查詢展示的頁面。如下圖
image.png

export SPAN_STORAGE_TYPE=elasticsearch
nohup ./jaeger-query --span-storage.type=elasticsearch --es.server-urls=ttp://127.0.0.1:9200 --es.username=* --es.password=*  --es.index-prefix=online --es.timeout=10s > query.log 2>&1 &
啓動查詢命令,注意index-prefix 是你的ES索引前綴,方便聚合查詢的。

Http 註冊

服務啓動時,加載全局trace。

func init() {
    binaryName := strings.Split(os.Args[0], "/")
    statMetric := binaryName[len(binaryName)-1]
    InitTracing(statMetric, 0, 0)
}

func InitTracing(serviceName string, maxIdleConns, maxIdleConnsPerHost int) {
    c := config.Configuration{
        Sampler: &config.SamplerConfig{Type: jaeger.SamplerTypeRemote}, // SamplingServerURL: "http://localhost:5778/sampling"
        Reporter: &config.ReporterConfig{
            LogSpans:            false,
            BufferFlushInterval: 60 * time.Second,
            LocalAgentHostPort:  "127.0.0.1:6831",
        }}
    if closer != nil {
        closer.Close()
    }
    var err error
    closer, err = c.InitGlobalTracer(serviceName)
    if err != nil {
        log.Error(err)
        panic(err)
    }
    DefaultHTTPClient = &http.Client{Transport: NewHTTPTransport(opentracing.GlobalTracer(), maxIdleConns, maxIdleConnsPerHost)}

}

transport 內嵌 OK,搞定

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
    rt := t.RoundTripper
    if rt == nil {
        rt = http.DefaultTransport
    }
    tracer, ok := req.Context().Value(keyTracer).(*RequestTracer)
    if !ok {
        return rt.RoundTrip(req)
    }

    tracer.start(req)

    ext.HTTPMethod.Set(tracer.sp, req.Method)
    ext.HTTPUrl.Set(tracer.sp, req.URL.String())

    carrier := opentracing.HTTPHeadersCarrier(req.Header)
    tracer.sp.Tracer().Inject(tracer.sp.Context(), opentracing.HTTPHeaders, carrier)
    resp, err := rt.RoundTrip(req)

    if err != nil {
        return resp, err
    }
    ext.HTTPStatusCode.Set(tracer.sp, uint16(resp.StatusCode))
    if req.Method == "HEAD" {
    } else {
        resp.Body = closeTracker{resp.Body, tracer.sp}
    }
    return resp, nil
}

業務埋點註冊

當我們是業務內部的函數/日誌需要上報到全鏈路時候如何做那?

var Trace opentracing.Tracer
var Closer io.Closer

func NewTrace(srv string) {
    Trace, Closer = InitJaeger(srv)
    if Closer != nil {

    }
    opentracing.InitGlobalTracer(Trace)
}

//記錄推送 的trace info
type PushTrace struct {
    Ctx      context.Context
    IsRecord bool //是否記錄  true 記錄
}

func NewPushContext(isRecord bool, span opentracing.Span) (trace PushTrace) {
    if !isRecord {
        trace = PushTrace{IsRecord: isRecord}
    } else {
        trace = PushTrace{
            Ctx:      opentracing.ContextWithSpan(context.Background(), span),
            IsRecord: isRecord,
        }
    }
    return trace
}

//簡單追加span
func AppendSpan(trace PushTrace, operationName string, event, val string) {
    if trace.IsRecord {
        span, ctx := opentracing.StartSpanFromContext(trace.Ctx, operationName)
        opentracing.ContextWithSpan(ctx, span)
        span.LogFields(
            opentracinglog.String("event", event),
            opentracinglog.String("value", val),
        )
        defer span.Finish()
    }
}

調用示例


span := Trace.StartSpan("***")
    span.SetTag("push_id","test")
    span.Finish()
    trace := NewPushContext(true, span)
    
    //函數1
    AppendSpan(trace, "test1", "android", "nopush")

如圖image.png

代碼地址

https://github.com/xiaowei520/golangx/tree/master/trace

參考文章

https://opentracing.io

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章