泽注:这是一个系列,共分成6部分,这是第5部分。翻译自:https://trstringer.com/otel-part5-propagation/
我们开发的应用程序各式各样的,有些是单体的,有些是微服务的。单体应用添加遥测相当容易,因为所有的数据都在同一进程中。但是,微服务就有挑战了。很多时候,它只是连接分布式应用之间不同服务的网络。即使这样,这个挑战也无法阻止我们建立有效的链路追踪,如下图:
即使是微服务应用,我们也希望看到一个类似的追踪,追踪用户的路径从开始到结束,即使是跨越多个服务的边界。这就是我们所说的分布式跟踪。但是我们怎样才能实现这一点呢?我们怎样才能追踪跨越多个进程的链路,这些进程还可能运行在非常不同的基础设施上?
传播(Propagation)
OpenTelemetry 对这一挑战的回答是传播。这就是我们如何将追踪 ID(和父跨度 ID)传输到被调用的服务,以便它们可以将跨度添加到分布式调用链中。可视化后如下:
这三个服务,通过使用传播,我们能够将跟踪 ID 和父跨度 ID 作为header进行传输。在 Go 中,我们可以通过全局设置来处理传播:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
// ...
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{}),
)
在服务器实例化过程中,我们可以在处理器级别设置:
http.Handle(
fmt.Sprintf("/%s/", rootPath),
otelhttp.NewHandler(
http.HandlerFunc(userCart),
"http_user_cart",
otelhttp.WithTracerProvider(otel.GetTracerProvider()),
otelhttp.WithPropagators(otel.GetTextMapPropagator()),
))
当我从该服务向其他服务发出 HTTP 请求时,我可以使用 otelhttp
添加辅助函数以向请求添加跨度:
import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
// ...
resp, err := otelhttp.Get(ctx, fmt.Sprintf("%s/%s", userServiceEndpoint, userName))
背包(Baggage)
在上图中,您会注意到“service 1”生成了一些名为“attr1”的数据。这是与“service 1”相关的数据,这可能是我们想要添加到“service 2”和/或“service 3”中的跨度的属性。但是这些服务可能无法访问这些特定数据。我们使用 OpenTelemetry 解决这个问题的方法是使用 baggage。 Baggage 本质上允许我们通过请求传递数据以供其他服务使用。
在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)
现在我们的HTTP请求中将带有baggage req.addr
。
在消费服务中(在图中,这可能是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中取出数据,并将其它作为跨度属性写入到当前跨度。
案例
我们已经谈到了传播和baggage,但现在让我们看看OpenTelemetry是如何发送这些数据的。在我的示例购物车应用中,如果我发起一个请求,并从价格或用户服务中转储header信息,那么我将看到以下两个头信息:
Baggage: req.addr=10.244.0.11%3A60086
Traceparent: 00-9861e8c7b097206fed82e0f6b379aae0-4aa019606aed70b6-01
traceparent
头显示了trace ID(在本例中是 "9861e8c7b097206fed82e0f6b379aae0")和父跨度ID("4aa019606aed70b6")。还有一个baggage
头,包括在源服务(购物车)中添加的req.addr
baggage成员。我们可以看到这个baggage在用户服务中被引用:
总结
OpenTelemetry对 "分布式跟踪 "的 "分布式 "部分有很好的支持,通过传播和baggage的使用。这真的让你有能力做出有意义的追踪,并收集有用的数据!