Jaeger全鏈路go實現,包含http和消息隊列的鏈式傳遞


Jaeger全鏈路go實現,包含http和消息隊列的鏈式傳遞

完整代碼

https://github.com/werbenhu/jaeger-go-demo
同時,我提供了一個封裝好的版本,更方便使用請參考
https://github.com/werbenhu/jaeger-go

本地鏈路

本地鏈路,不涉及到trace-id跨服務器傳遞。
通過opentracing.StartSpanFromContext即可完成,父span和子span關系
如下代碼:

	tracer := opentracing.GlobalTracer()
	//創建根span
	rootSpan, rootCtx := opentracing.StartSpanFromContext(context.Background(), "root-span")
	//...
	//創建子span
	subSpan, subCtx := opentracing.StartSpanFromContext(rootCtx, "sub-span")
	//...
	//...
	subSpan.Finish()
	//...
	rootSpan.Finish()
	//...
http跨服務

http跨服務需要解決trace-id傳遞的問題,參考下面的文檔
https://github.com/opentracing/opentracing-go
https://opentracing.io/docs/overview/inject-extract/

客戶端請求的時候需要將trace-id放到header中

	client := &http.Client{}
	req, _ := http.NewRequest("GET","http://localhost:9002/server_two",nil)

	// refer to https://github.com/opentracing/opentracing-go
	// refer to https://opentracing.io/docs/overview/inject-extract/
	tracer := opentracing.GlobalTracer()
	// 生成一個請求的span
	clientSpan, clientCtx := opentracing.StartSpanFromContext(ctx, "http-one-req")
	carrier := opentracing.HTTPHeadersCarrier{}
	tracer.Inject(clientSpan.Context(), opentracing.HTTPHeaders, carrier)

	// 將當前span的trace-id傳遞到http header中
	for key, value := range carrier {
		req.Header.Add(key, value[0])
	}

	// 發送請求
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	//結束當前請求的span
	clientSpan.Finish()

服務器端要拿到客戶端傳遞過來的trace-id,然后創建一個基於該trace-id的子span
也就是認客戶端為父

	// 從http頭中提取trace-id
	// refer to https://github.com/opentracing/opentracing-go
	// refer to https://opentracing.io/docs/overview/inject-extract/
	carrier := opentracing.HTTPHeadersCarrier{}
	carrier.Set("uber-trace-id", c.GetHeader("uber-trace-id"))

	tracer := opentracing.GlobalTracer()
	wireContext, err := tracer.Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(c.Request.Header))
	if err != nil {
		log.Fatal(err)
	}

	// 由傳遞過來的trace-id作為父span
	serverSpan := opentracing.StartSpan(
		"server-two-http-root",
		ext.RPCServerOption(wireContext))

	ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
	selfCall(ctx)

		c.JSON(200, gin.H{
			"message": "server two response",
		})
		serverSpan.Finish()
消息隊列實現全鏈路


這里以nsq為例
生產者將trace-id封裝到msg中

	tracer := opentracing.GlobalTracer()
	clientSpan, clientCtx := opentracing.StartSpanFromContext(ctx, "nsq-one-req")
	carrier := opentracing.HTTPHeadersCarrier{}
	tracer.Inject(clientSpan.Context(), opentracing.HTTPHeaders, carrier)

	// 將trace-id封裝到消息中,由消息隊列,傳給消費者
	msg, _ := json.Marshal(carrier)
	// 生產消息
	Produce(TopicName, string(msg))

	clientSpan.Finish()
	return clientCtx

消費者將trace-id取出,並創建基於該trace-id的子span,相當於認生產者為父

// 消費者消息處理,處理server-one發送過來的消息
func eventHandler(message string) error {
	fmt.Printf("event msg:%s\n", message)

	jaeger := initJaeger("two1")
	defer jaeger.Close()

	// 讀取消息中的trace-id
	var carrier opentracing.HTTPHeadersCarrier
	json.Unmarshal([]byte(message), &carrier)

	tracer := opentracing.GlobalTracer()
	wireContext, err := tracer.Extract(
		opentracing.HTTPHeaders,
		carrier)
	if err != nil {
		log.Fatal(err)
	}

	// 由傳遞過來的trace-id作為父span
	serverSpan := opentracing.StartSpan(
		"nsq_two",
		ext.RPCServerOption(wireContext))

	ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
	selfCall(ctx)
	serverSpan.Finish()

	return nil
}


免責聲明!

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



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