基于OpenTelemetry实现可观测性-Part 5 传播与Baggage

8af1363e3c07c9efa78f4bad79dc3b3c.jpeg

泽注:这是一个系列,共分成6部分,这是第5部分。翻译自:https://trstringer.com/otel-part5-propagation/

我们开发的应用程序各式各样的,有些是单体的,有些是微服务的。单体应用添加遥测相当容易,因为所有的数据都在同一进程中。但是,微服务就有挑战了。很多时候,它只是连接分布式应用之间不同服务的网络。即使这样,这个挑战也无法阻止我们建立有效的链路追踪,如下图:

61b0999c8fcc1cdd7fbd340e7bbef81a.png
传播

即使是微服务应用,我们也希望看到一个类似的追踪,追踪用户的路径从开始到结束,即使是跨越多个服务的边界。这就是我们所说的分布式跟踪。但是我们怎样才能实现这一点呢?我们怎样才能追踪跨越多个进程的链路,这些进程还可能运行在非常不同的基础设施上?

传播(Propagation)

OpenTelemetry 对这一挑战的回答是传播。这就是我们如何将追踪 ID(和父跨度 ID)传输到被调用的服务,以便它们可以将跨度添加到分布式调用链中。可视化后如下:

70dcebb5fd018833aad8d2a9cc9ca9f9.png
Propagation

这三个服务,通过使用传播,我们能够将跟踪 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 2service 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在用户服务中被引用:

8d9dc8518f27ac4d386a348cecd1a6b1.png
baggage

总结

OpenTelemetry对 "分布式跟踪 "的 "分布式 "部分有很好的支持,通过传播和baggage的使用。这真的让你有能力做出有意义的追踪,并收集有用的数据!

猜你喜欢

转载自blog.csdn.net/apl359/article/details/129980339