GoFrame 鏈路跟蹤-背景知識(shí)

2022-04-01 14:29 更新

一、OpenTelemetry

分布式鏈路跟蹤( ?Distributed Tracing? )的概念最早是由?Google?提出來(lái)的,發(fā)展至今技術(shù)已經(jīng)比較成熟,也是有一些協(xié)議標(biāo)準(zhǔn)可以參考。目前在?Tracing?技術(shù)這塊比較有影響力的是兩大開(kāi)源技術(shù)框架:?Netflix?公司開(kāi)源的?OpenTracing?和?Google?開(kāi)源的?OpenCensus?。兩大框架都擁有比較高的開(kāi)發(fā)者群體。為形成統(tǒng)一的技術(shù)標(biāo)準(zhǔn),兩大框架最終磨合成立了?OpenTelemetry?項(xiàng)目,簡(jiǎn)稱?otel?。具體可以參考:

因此,我們的?Tracing?技術(shù)方案以?OpenTelemetry?為實(shí)施標(biāo)準(zhǔn),協(xié)議標(biāo)準(zhǔn)的一些Golang實(shí)現(xiàn)開(kāi)源項(xiàng)目:

https://github.com/open-telemetry/opentelemetry-go

https://github.com/open-telemetry/opentelemetry-go-contrib

其他第三方的框架和系統(tǒng)(如?Jaeger/Prometheus/Grafana?等)也會(huì)按照標(biāo)準(zhǔn)化的規(guī)范來(lái)對(duì)接?OpenTelemetry?,使得系統(tǒng)的開(kāi)發(fā)和維護(hù)成本大大降低。


二、重要概念

我們先看看?OpenTelemetry?的架構(gòu)圖,我們這里不會(huì)完整介紹,只會(huì)介紹其中大家常用的幾個(gè)概念。關(guān)于?OpenTelemetry?的內(nèi)部技術(shù)架構(gòu)設(shè)計(jì)介紹,可以參考 ?OpenTelemetry?架構(gòu) ,關(guān)于語(yǔ)義約定請(qǐng)參考:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md


TracerProvider

主要負(fù)責(zé)創(chuàng)建?Tracer?,一般是需要第三方的分布式鏈路跟蹤管理平臺(tái)提供具體的實(shí)現(xiàn)。默認(rèn)情況是一個(gè)空的?TracerProvider (NoopTracerProvider)?,雖然也能創(chuàng)建?Tracer?但是內(nèi)部其實(shí)不會(huì)執(zhí)行具體的數(shù)據(jù)流傳輸邏輯。

Tracer

?Tracer?表示一次完整的追蹤鏈路,?tracer?由一個(gè)或多個(gè)?span?組成。下圖示例表示了一個(gè)由8個(gè)?span?組成的?tracer?:

        [Span A]  ←←←(the root span)
            |
     +------+------+
     |             |
 [Span B]      [Span C] ←←←(Span C is a `ChildOf` Span A)
     |             |
 [Span D]      +---+-------+
               |           |
           [Span E]    [Span F] >>> [Span G] >>> [Span H]
                                       ↑
                                       ↑
                                       ↑
                         (Span G `FollowsFrom` Span F)

時(shí)間軸的展現(xiàn)方式會(huì)更容易理解:

––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

 [Span A···················································]
   [Span B··············································]
      [Span D··········································]
    [Span C········································]
         [Span E·······]        [Span F··] [Span G··] [Span H··]

我們通常通過(guò)以下方式創(chuàng)建一個(gè)?Tracer?:

gtrace.NewTracer(tracerName)

Span

?Span?是一條追蹤鏈路中的基本組成要素,一個(gè)?span?表示一個(gè)獨(dú)立的工作單元,比如可以表示一次函數(shù)調(diào)用,一次?http?請(qǐng)求等等。?span?會(huì)記錄如下基本要素:

  • 服務(wù)名稱(?operation name?)
  • 服務(wù)的開(kāi)始時(shí)間和結(jié)束時(shí)間
  • ?K/V?形式的?Tags ?
  • ?K/V?形式的?Logs ?
  • ?SpanContext ?

?Span?是這么多對(duì)象中使用頻率最高的,因此創(chuàng)建?Span?也非常簡(jiǎn)便,例如:

gtrace.NewSpan(ctx, spanName, opts...)

Attributes

?Attributes?以?K/V?鍵值對(duì)的形式保存用戶自定義標(biāo)簽,主要用于鏈路追蹤結(jié)果的查詢過(guò)濾。例如:http.method="GET",http.status_code=200?。其中?key?值必須為字符串,?value?必須是字符串,布爾型或者數(shù)值型。  ?span?中的?Attributes?僅自己可見(jiàn),不會(huì)隨著?SpanContext?傳遞給后續(xù)?span?。 設(shè)置?Attributes?方式例如:

span.SetAttributes(
	label.String("http.remote", conn.RemoteAddr().String()),
	label.String("http.local", conn.LocalAddr().String()),
)
    

Events

?Events?與?Attributes?類似,也是?K/V?鍵值對(duì)形式。與?Attributes?不同的是,?Events?還會(huì)記錄寫(xiě)入?Events?的時(shí)間,因此?Events?主要用于記錄某些事件發(fā)生的時(shí)間。?Events?的?key?值同樣必須為字符串,但對(duì)?value?類型則沒(méi)有限制。例如:

span.AddEvent("http.request", trace.WithAttributes(
	label.Any("http.request.header", headers),
	label.Any("http.request.baggage", gtrace.GetBaggageMap(ctx)),
	label.String("http.request.body", bodyContent),
))
        

SpanContext

?SpanContext?攜帶著一些用于跨服務(wù)通信的(跨進(jìn)程)數(shù)據(jù),主要包含:

  • 足夠在系統(tǒng)中標(biāo)識(shí)該?span?的信息,比如:?span_id?, ?trace_id?。
  • ?Baggage?-為整條追蹤連保存跨服務(wù)(跨進(jìn)程)的?K/V?格式的用戶自定義數(shù)據(jù)。?Baggage? 與 ?Attributes? 類似,也是 ?K/V? 鍵值對(duì)。與Attributes不同的是:
    • 其?key?跟?value?都只能是字符串格式
    • ?Baggage?不僅當(dāng)前?span?可見(jiàn),其會(huì)隨著?SpanContext?傳遞給后續(xù)所有的子?span?。要小心謹(jǐn)慎的使用?Baggage- 因?yàn)樵谒械?span?中傳遞這些?K,V?會(huì)帶來(lái)不小的網(wǎng)絡(luò)和?CPU?開(kāi)銷(xiāo)。

Propagator

?Propagator?傳播器用于端對(duì)端的數(shù)據(jù)編碼/解碼,例如:?Client?到?Server?端的數(shù)據(jù)傳輸,?TraceId?、?SpanId?和?Baggage?也是需要通過(guò)傳播器來(lái)管理數(shù)據(jù)傳輸。業(yè)務(wù)端開(kāi)發(fā)者往往對(duì)?Propagator?無(wú)感知,只有中間件/攔截器的開(kāi)發(fā)者需要知道它的作用。?OpenTelemetry?的標(biāo)準(zhǔn)協(xié)議實(shí)現(xiàn)庫(kù)提供了常用的?TextMapPropagator?,用于常見(jiàn)的文本數(shù)據(jù)端到端傳輸。此外,為保證?TextMapPropagator?中的傳輸數(shù)據(jù)兼容性,不應(yīng)當(dāng)帶有特殊字符,具體請(qǐng)參考:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md

?GoFrame?框架通過(guò)?gtrace 模塊使用了以下傳播器對(duì)象,并全局設(shè)置到了?OpenTelemetry?中:

// defaultTextMapPropagator is the default propagator for context propagation between peers.
defaultTextMapPropagator = propagation.NewCompositeTextMapPropagator(
	propagation.TraceContext{},
	propagation.Baggage{},
)

三、支持組件

?GoFrame?的核心組件都已經(jīng)全面支持?OpenTelemetry?標(biāo)準(zhǔn),并且自動(dòng)開(kāi)啟了鏈路跟蹤特性,開(kāi)發(fā)者無(wú)需顯示調(diào)用、使用無(wú)感知。在沒(méi)有注入外部?TracerProvider?的情況下,框架會(huì)使用默認(rèn)的?TracerProvider?,該?TracerProvider?只會(huì)自動(dòng)創(chuàng)建?TraceID?及?SpanID?,并不會(huì)執(zhí)行復(fù)雜邏輯。

包括但不限于以下核心組件:

  • ?Http Client ?

?HTTP?客戶端自動(dòng)啟用了鏈路跟蹤特性。

  • ?Http Server ?

?HTTP?服務(wù)端自動(dòng)啟用了鏈路跟蹤特性。

  • ?gRPC Client ?

?gRPC?客戶端自動(dòng)啟用了鏈路跟蹤特性。

  • ?gRPC Server ?

?gRPC?服務(wù)端自動(dòng)啟用了鏈路跟蹤特性。

  • ?Logging ?

日志內(nèi)容中需要注入當(dāng)前請(qǐng)求的?TraceId?,以方便通過(guò)日志快速查找定位問(wèn)題點(diǎn)。該特性是由?glog?組件實(shí)現(xiàn),這需要開(kāi)發(fā)者在輸出日志的時(shí)候調(diào)用?Ctx?鏈?zhǔn)讲僮鞣椒▽?context.Context?上下文變量傳遞到當(dāng)前輸出日志操作鏈路中,沒(méi)有傳遞?context.Context?上下文變量,就會(huì)丟失日志內(nèi)容中的?TraceId?。

  • ?ORM ?

數(shù)據(jù)庫(kù)的執(zhí)行是很重要的鏈路環(huán)節(jié),?Orm?組件需要將自身的執(zhí)行情況投遞到鏈路中,作為執(zhí)行鏈路的一部分。

  • ?Redis ?

?Redis?的執(zhí)行也是很重要的鏈路環(huán)節(jié),?Redis?需要將自身的執(zhí)行情況投遞到鏈路中,作為執(zhí)行鏈路的一部分。

  • ?Utils ?

對(duì)于?Tracing?特性的管理需要做一定的封裝,主要考慮的是可擴(kuò)展性和易用性兩方面。該封裝由?gtrace?模塊實(shí)現(xiàn),文檔地址:https://pkg.go.dev/github.com/gogf/gf/v2/net/gtrace


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)