澤注:這是一個系列,共分成6部分,這是第5部分。翻譯自:https://trstringer.com/otel-part5-propagation/
我們開發(fā)的應(yīng)用程序各式各樣的,有些是單體的供炎,有些是微服務(wù)的渴逻。單體應(yīng)用添加遙測相當(dāng)容易,因為所有的數(shù)據(jù)都在同一進(jìn)程中音诫。但是惨奕,微服務(wù)就有挑戰(zhàn)了。很多時候竭钝,它只是連接分布式應(yīng)用之間不同服務(wù)的網(wǎng)絡(luò)梨撞。即使這樣,這個挑戰(zhàn)也無法阻止我們建立有效的鏈路追蹤蜓氨,如下圖:
即使是微服務(wù)應(yīng)用聋袋,我們也希望看到一個類似的追蹤,追蹤用戶的路徑從開始到結(jié)束穴吹,即使是跨越多個服務(wù)的邊界幽勒。這就是我們所說的分布式跟蹤。但是我們怎樣才能實現(xiàn)這一點(diǎn)呢港令?我們怎樣才能追蹤跨越多個進(jìn)程的鏈路啥容,這些進(jìn)程還可能運(yùn)行在非常不同的基礎(chǔ)設(shè)施上?
傳播(Propagation)
OpenTelemetry 對這一挑戰(zhàn)的回答是傳播顷霹。這就是我們?nèi)绾螌⒆粉?ID(和父跨度 ID)傳輸?shù)奖徽{(diào)用的服務(wù)咪惠,以便它們可以將跨度添加到分布式調(diào)用鏈中×艿恚可視化后如下:
這三個服務(wù)遥昧,通過使用傳播,我們能夠?qū)⒏?ID 和父跨度 ID 作為header進(jìn)行傳輸朵纷。在 Go 中炭臭,我們可以通過全局設(shè)置來處理傳播:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
// ...
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{}),
)
在服務(wù)器實例化過程中,我們可以在處理器級別設(shè)置:
http.Handle(
fmt.Sprintf("/%s/", rootPath),
otelhttp.NewHandler(
http.HandlerFunc(userCart),
"http_user_cart",
otelhttp.WithTracerProvider(otel.GetTracerProvider()),
otelhttp.WithPropagators(otel.GetTextMapPropagator()),
))
當(dāng)我從該服務(wù)向其他服務(wù)發(fā)出 HTTP 請求時袍辞,我可以使用 otelhttp
添加輔助函數(shù)以向請求添加跨度:
import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
// ...
resp, err := otelhttp.Get(ctx, fmt.Sprintf("%s/%s", userServiceEndpoint, userName))
背包(Baggage)
在上圖中鞋仍,您會注意到“service 1”生成了一些名為“attr1”的數(shù)據(jù)。這是與“service 1”相關(guān)的數(shù)據(jù)搅吁,這可能是我們想要添加到“service 2”和/或“service 3”中的跨度的屬性威创。但是這些服務(wù)可能無法訪問這些特定數(shù)據(jù)。我們使用 OpenTelemetry 解決這個問題的方法是使用 baggage谎懦。 Baggage 本質(zhì)上允許我們通過請求傳遞數(shù)據(jù)以供其他服務(wù)使用肚豺。
在Go中,我們增加baggage的方法如下:
reqAddrBaggage, err := baggage.NewMember("req.addr", r.RemoteAddr)
if err != nil {
// Handle error...
}
reqBaggage, err := baggage.New(reqAddrBaggage)
if err != nil {
// Handle error...
}
ctx = baggage.ContextWithBaggage(ctx, reqBaggage)
現(xiàn)在我們的HTTP請求中將帶有baggage req.addr
界拦。
在消費(fèi)服務(wù)中(在圖中详炬,這可能是service 2
或service 3
),對從baggage中解析請求:
import "go.opentelemetry.io/otel/baggage"
// ...
reqBaggage := baggage.FromContext(ctx)
span.SetAttributes(attribute.String(
"req.addr",
reqBaggage.Member("req.addr").Value()),
)
該代碼從請求baggage中取出數(shù)據(jù),并將其它作為跨度屬性寫入到當(dāng)前跨度呛谜。
案例
我們已經(jīng)談到了傳播和baggage,但現(xiàn)在讓我們看看OpenTelemetry是如何發(fā)送這些數(shù)據(jù)的枪萄。在我的示例購物車應(yīng)用中隐岛,如果我發(fā)起一個請求,并從價格或用戶服務(wù)中轉(zhuǎn)儲header信息瓷翻,那么我將看到以下兩個頭信息:
Baggage: req.addr=10.244.0.11%3A60086
Traceparent: 00-9861e8c7b097206fed82e0f6b379aae0-4aa019606aed70b6-01
traceparent
頭顯示了trace ID(在本例中是 "9861e8c7b097206fed82e0f6b379aae0")和父跨度ID("4aa019606aed70b6")聚凹。還有一個baggage
頭,包括在源服務(wù)(購物車)中添加的req.addr
baggage成員齐帚。我們可以看到這個baggage在用戶服務(wù)中被引用:
總結(jié)
OpenTelemetry對 "分布式跟蹤 "的 "分布式 "部分有很好的支持妒牙,通過傳播和baggage的使用。這真的讓你有能力做出有意義的追蹤对妄,并收集有用的數(shù)據(jù)湘今!