什么是鏈路追蹤
借用阿里云鏈路追蹤檔案來解釋
分布式鏈路追蹤(Distributed Tracing),也叫 分布式鏈路跟蹤,分布式跟蹤,分布式追蹤 等等,它為分布式應用的開發者提供了完整的呼叫鏈路還原、呼叫請求量統計、鏈路拓撲、應用依賴分析等工具,可以幫助開發者快速分析和診斷分布式應用架構下的性能瓶頸,提高微服務時代下的開發診斷效率,
為了應對各種復雜的業務,開發工程師開始采用敏捷開發、持續集成等開發方式,系統架構也從單機大型軟體演化成微服務架構,微服務構建在不同的軟體集上,這些軟體模塊可能是由不同團隊開發的,可能使用不同的編程語言來實作,還可能發布在多臺服務器上,因此,如果一個服務出現問題,可能導致幾十個應用都出現服務例外,
分布式追蹤系統可以記錄請求范圍內的資訊,例如一次遠程方法呼叫的執行程序和耗時,是我們排查系統問題和系統性能的重要工具,
呼叫鏈
在廣義上,一個呼叫鏈代表一個事務或者流程在(分布式)系統中的執行程序,在OpenTracing標準中,呼叫鏈是多個Span組成的一個有向無環圖(Directed Acyclic Graph,簡稱DAG),每一個Span代表呼叫鏈中被命名并計時的連續性執行片段,
下圖是一個分布式呼叫的例子:客戶端發起請求,請求首先到達負載均衡器,接著經過認證服務、計費服務,然后請求資源,最后回傳結果,
圖 1. 分布式呼叫示例

資料被采集存盤后,分布式追蹤系統一般會選擇使用包含時間軸的時序圖來呈現這個呼叫鏈,
圖 2. 包含時間軸的鏈路圖

追蹤資訊
追蹤資訊包含時間戳、事件、方法名(Family+Title)、注釋(TAG/Comment),
客戶端和服務器上的時間戳來自不同的主機,我們必須考慮到時間偏差,RPC 客戶端發送一個請求之后,服務器端才能接收到,對于回應也是一樣的(服務器先回應,然后客戶端才能接收到這個回應),這樣一來,服務器端的 RPC 就有一個時間戳的一個上限和下限,
追蹤采樣
鏈路追蹤在生成追蹤和收集追蹤資料的時候會消耗系統資源,在服務高負載情況下可能會導致系統性能下降,因為在鏈路追蹤上可以參考跟蹤采樣的思路降低鏈路追蹤的消耗,
- 固定采樣(1/1024)
這種采樣方案對于高吞吐高負載的線上服務來說相當有用,在大吞吐量的情況下某些事件仍然可能經常出現,并且被采樣到,但是在比較低的負載情況下這種采樣方式往往可能會漏掉某些重要事件,而選擇較高的采樣率就需要接受性能損耗, - 積極采樣
在低負載情況下固定采樣無法采集到重要資料的情況下,可以采用動態的積極采樣方式,例如在高QPS情況下采樣率下降,低QPS下提高采樣率,
如何使用
目前業界開源的知名鏈路追蹤系統比如Google的Dapper,Twitter的zipkin,淘寶的鷹眼,新浪的Watchman,京東的Hydra等
而本文則使用Jaeger來作為鏈路追蹤系統
簡單用docker起一個jaeger
docker run -d -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 14269:14269 -p 9411:9411 jaegertracing/all-in-one:latest
訪問127.0.0.1:16686
看到這個頁面就OK了

在kratos中植入鏈路追蹤
根據官方檔案kratos 框架提供的自帶中間件中有一個名為 tracing 中間件,它基于 Opentelemetry 實作了kratos 框架的鏈路追蹤功能
- 在main.go中構建鏈路追蹤
//構建全鏈路追蹤
// tracerProvider returns an OpenTelemetry TracerProvider configured to use
// the Jaeger exporter that will send spans to the provided url. The returned
// TracerProvider will also use a Resource configured with all the information
// about the application.
func tracerProvider(url string) (*trace.TracerProvider, error) {
// Create the Jaeger exporter
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
if err != nil {
return nil, err
}
tp := trace.NewTracerProvider(
// Always be sure to batch in production.
trace.WithBatcher(exp),
// Record information about this application in an Resource.
trace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(Name), //實體名稱
attribute.String("environment", Name), // 相關環境
attribute.String("ID", Version), //版本
)),
)
return tp, nil
}
- 在main方法中呼叫tracerProvider
//啟動鏈路追蹤
tp, err := tracerProvider(config.GetConfig().GetString("jaeger.ipaddr"))
if err != nil {
panic(err)
}
//將tp作為全域鏈路追蹤的提供程式
otel.SetTracerProvider(tp)
- 在client和server端加上鏈路追蹤中間件
server端
//grpc
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(),
logging.Server(logger), //日志中間件
tracing.Server(), //鏈路追蹤中間件
),
}
//http
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
logging.Server(logger), //日志中間件
tracing.Server(), //鏈路追蹤中間件
),
}
client端
grpc.WithMiddleware(
recovery.Recovery(),
logging.Client(logger), //日志中間件,
tracing.Client(), //鏈路追蹤中間件
),
啟動server端和client端,訪問一下介面
可以發現jaeger上成功監測到請求鏈路

拓撲圖也成功展示出來

References
https://go-kratos.dev/blog/go-kratos-opentelemetry-practice
https://www.jianshu.com/p/07cf4093536a?from=singlemessage
https://help.aliyun.com/document_detail/90277.html?spm=5176.22294701.J_5253785160.4.49451088XuirYu
如有錯誤請留言反饋
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/348145.html
標籤:Go
