在 Knative 中进行分布式跟踪

在本文中,您将了解在 Knative 中进行分布式跟踪的工作原理,并探索 OpenTelemetry 项目如何使该环境中的跟踪支持更容易实现。我们将深入了解 Knative 的内部结构,以了解它提供的开箱即用的分布式跟踪功能以及系统中需要进行其他注入的部分。

关于 Knative

Knative 是构建在 Kubernetes 之上的无服务器平台,作为一组CustomResourceDefinitions(CRD)。该项目分为两个逻辑部分:

  • serving(服务)——促进工作负载/服务的创建、部署和扩展
  • eventing(事件)——促进工作负载之间的事件驱动通信,实现松耦合架构

在本文中,我们不会介绍 Knative 的基础知识,请参阅Knative 文档以熟悉该项目。

Knative 数据流

在深入研究跟踪之前,让我们先看一个数据流示例。这将帮助我们了解 Knative 的架构以及系统的哪些部分需要进行注入,以了解请求或事务的时间特性。在下面的图表中,有两个用户工作负载(第一个和第二个),以及一个标记为(1. HTTP)的传入请求,该请求首先经过第一个工作负载,然后经过云事件消息到达第二个工作负载。

Knative 数据流:传入的 HTTP 请求经过 Knative 服务和 queue-proxy sidecar 容器,然后到达工作负载

关于这个图表有两个重要的事实:

  1. 所有流量都经过 queue-proxy sidecar。
  2. 所有流量都经过 Knative 的组件。图表中的 Knative 组件是抽象的。可以是 Knative 激活器服务、Knative 事件代理、调度器等。

从遥测的角度来看,queue-proxy 的作用类似于 Istio 服务网格中的 istio-proxy。它是一个拦截传递给工作负载的所有流量的代理,并为任何与工作负载进行的通信发出遥测数据。

Knative 中的分布式跟踪

Knative 项目内置了强大的分布式跟踪集成。系统的主要部分已经进行了注入,并且系统会为发送到用户工作负载的事务/请求创建跟踪数据。

目前,Knative 内部使用 OpenCensus 注入库以 Zipkin 格式导出数据。进程间上下文传播使用Zipkin B3W3C Trace-Context标准。出于传统原因,Zipkin B3 传播格式可能是为了兼容使用旧技术进行注入的旧工作负载的轨迹传播。作为最佳实践,请使用标准的 W3C Trace-Context,这是 OpenTelemetry 项目原生支持的。

现在让我们来看一个示例跟踪,它涉及两个工作负载(第一个和第二个)。工作流与前一节中的图表类似:第一个服务接收到一个 HTTP 调用,并向第二个服务发送一个云事件。完整的演示源代码可以在 pavolloffay/knative-tracing 中找到。

Jaeger 屏幕截图显示了一个 Knative 跟踪

此跟踪显示了以下服务的相互作用:激活器、第一个工作负载、经纪人入口、imc 调度器、经纪人过滤器、激活器和第二个工作负载。好多个服务,是吧?只是两个工作负载之间的简单交互就产生了一个显示了许多 Knative 内部组件的跟踪。从可观测性的角度来看,这非常好,因为它可以显示基础架构中的问题,并进一步显示与 Knative 请求处理相关的成本。

让我们简要地说明一下数据流。传入的 HTTP 请求首先经过激活器服务,该服务负责扩展工作负载,然后执行到达第一个工作负载。第一个工作负载发送一个云事件,云事件经过经纪人和调度器,最后到达第二个工作负载。

现在让我们更详细地看一下用户工作负载。第一个服务是一个使用 Golang 编写的服务,具有一个单一的 REST API 端点。端点实现创建一个云事件并将其发送到经纪人。让我们从可观测性的角度来看一下重要的事实:

  • REST API 使用 OpenTelemetry 进行了注入。这使我们能够将在 Knative 激活器服务中启动的跟踪与在工作负载中创建的 span 相关联,并将其与出站 span 相关联 - 例如,对第二个服务的调用。
  • 该工作负载正在使用已注入的 Cloudevents 客户端/SDK - 类似于前一点,它允许我们在传出请求中继续追踪(在这种情况下,是对第二个服务的请求)。

我们的示例应用程序中的跟踪上下文(traceIdspanIdsampled 标志)是如何传播的?跟踪上下文在 HTTP 标头中传播,既适用于传入到第一个服务的 HTTP 请求,也适用于发送到第二个服务的云事件。跟踪上下文不直接附加到事件的扩展/属性。

以下是第一个服务的日志输出,其中包含请求标头:

2022/02/17 12:53:48 Request headers:
2022/02/17 12:53:48 	X-B3-Sampled: [1]
2022/02/17 12:53:48 	X-B3-Spanid: [af6c239eb7b39349]
2022/02/17 12:53:48 	X-B3-Traceid: [5f2c4775e0e36efc1d554a0b6c456cc1]
2022/02/17 12:53:48 	X-Forwarded-For: [10.244.0.12, 10.244.0.5]
2022/02/17 12:53:48 	Accept-Language: [en,fr;q=0.9,de;q=0.8,sk;q=0.7]
2022/02/17 12:53:48 	Cookie: [_ga=GA1.2.260863911.1644918876]
2022/02/17 12:53:48 	Accept: [text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9]
2022/02/17 12:53:48 	K-Proxy-Request: [activator]
2022/02/17 12:53:48 	Upgrade-Insecure-Requests: [1]
2022/02/17 12:53:48 	User-Agent: [Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36]
2022/02/17 12:53:48 	X-Request-Id: [ee2797b5-1ee9-408e-b1ff-d5e5431977e6]
2022/02/17 12:53:48 	Cache-Control: [max-age=0]
2022/02/17 12:53:48 	X-Forwarded-Proto: [http]
2022/02/17 12:53:48 	Traceparent: [00-5f2c4775e0e36efc1d554a0b6c456cc1-af6c239eb7b39349-01]
2022/02/17 12:53:48 	Accept-Encoding: [gzip, deflate]
2022/02/17 12:53:48 	Forwarded: [for=10.244.0.12;proto=http]
2022/02/17 12:53:48 Response headers:
2022/02/17 12:53:48 	Traceparent: [00-5f2c4775e0e36efc1d554a0b6c456cc1-1cf3f827eba96bf2-01]
2022/02/17 12:53:48

现在让我们来看一下第二个服务的日志记录,该服务公开了用于接收 Knative 事件的 API。在这种情况下,事件 API 只是一个 HTTP 端点,这是一个云事件的实现细节:

2022/02/17 13:39:36 Event received: Context Attributes,
  specversion: 1.0
  type: httpbody
  source: github/com/pavolloffay
  id: fad4139c-b3fb-48b2-b0f4-fee44addc5f1
  time: 2022-02-17T13:39:34.426355726Z
  datacontenttype: text/plain
Extensions,
  knativearrivaltime: 2022-02-17T13:39:34.491325425Z
Data,
  hello from first, traceid=5f2c4775e0e36efc1d554a0b6c456cc1

我们可以看到跟踪上下文在事件对象中没有直接呈现。但是,它已编码在传入的传输消息 - HTTP 标头中。

未来改进

前面提到,Knative 的 serving 和 eventing 组件使用 OpenCensus SDK 进行了注入。将来,注入将更改为 OpenTelemetry,该更改在 knative/eventing/#3126knative/pkg#855 中有记录。SDK 的更改可能不会对用户产生直接影响,但它将使用户能够开始以 OpenTelemetry 格式(OTLP)本地报告数据。

另一个最近合并的更改是将Cloudevents 语义属性添加到 OpenTelemetry 规范中。该文档标准化了与 CloudEvents 相关的属性。下面的屏幕截图来自尚未使用标准属性名称的演示应用程序:

Jaeger 屏幕截图显示了 Knative 属性

配置

在 Knative 中,可以轻松启用跟踪。请按照 官方文档提供的逐步指南操作。这里简要描述一下该过程:

  1. 部署一个可以接收 Zipkin 格式跟踪数据的跟踪系统 - Zipkin、Jaeger 或 OpenTelemetry Collector
  2. Knative 事件中启用跟踪
  3. Knative 服务中启用跟踪

开始时,我建议使用100%的采样率配置来捕获群集中的所有流量的跟踪数据。这有助于避免采样问题,请不要忘记在切换到生产环境时更改此配置。

结论

我们了解了 Knative 项目提供的分布式跟踪功能,并了解了用户需要进行更多工作的部分。一般来说,Knative 会生成丰富的跟踪数据,但是,用户负责在工作负载中进行注入,并确保从传入请求或事件传播跟踪上下文。这与在服务网格中实现分布式跟踪的情况非常相似。

OpenTelemetry 可以帮助用户对工作负载进行注入,并正确传播跟踪上下文。根据所使用的语言,用户可以在代码中显式地初始化注入库,甚至可以动态注入 OpenTelemetry 自动注入工具到工作负载中

参考资料