使用 OpenTelemetry 在亚马逊 CloudFront 上设置端到端跟踪

在现代分布式系统中,确定问题发生的位置并不是一件容易的事。实际上,这是组织必须掌握的一项关键能力,才能保持其竞争力。追踪是用于此目的的好方法。它创建了一系列带有名为 Trace ID 的标识符的格式化日志,允许您按流经分布式系统的请求对日志进行分组。

当出现问题时,您的管理员可以通过查看跟踪日志轻松确定事情在哪里开始出现不同的行为。然后,您的团队可以专注于该特定领域,而不必对架构的每个部分进行一系列猜测。

尽管许多 亚马逊云科技 托管服务(例如 亚马逊 API Gatew ay)都支持 开箱即用的 亚马逊云科技 X- Ray 进行跟踪,但对大局的需求越来越大。与其查看从 API Gateway 开始的跟踪,不如从最初发出请求的位置一直看到跟踪信息。对更多选择的需求也越来越大。根据您的情况,您可能不会选择 亚马逊云科技 X-Ray 作为数据后端。相反,您可能需要将跟踪日志存储到文件系统或第三方解决方案。

为了满足这些需求,我们准备了一份使用 OpenTelemetry设置跟踪的分步指南, 该指南从亚马逊CloudFr on t开始。 你可以在 关联的 Git 存储库中找到这篇文章 中 使用的所有代码和资源 。本文中的概念适用于您想要设置端到端跟踪的任何情况。但是,请注意,我们在本文中用于资源的配置,例如 亚马逊云科技身份和访问管理 (IAM) 、CloudFront、A mazon OpenS earch 服务 、亚马逊 弹性负载均衡器 (Amazon ELB ) 、亚马逊 弹性容器注册表 (Amazon ECR ) 等,不适合按原样用于生产用途。如果您计划将这些概念应用到生产环境中,则需要进行全面的安全审查。

解决方案概述

Figure 1: Solution Architecture Overview

图 1:解决方案架构概述

我们演示了使用上述架构进行端到端跟踪。演示应用程序(“演示应用程序”)托管在 亚马逊弹性 Kubernetes 服务(亚马逊 EKS) 集群中, 用于处理最终用户请求。它的 API 端点通过 CloudFront 向公众公开。我们使用 OpenTelemetry 来跟踪用户对演示应用程序 API 的请求。

OpenTelemetr y 是一组 API、SDK、工具和集成,专为遥测数据(例如跟踪、指标和日志)而设计。它是以与供应商无关的方式生成和收集遥测数据的通用规范。我们使用 OpenTelemetry 来检测由 CloudFront 发行版和演示应用程序生成的跟踪日志。

更具体地说,我们使用 OpenTelemetry Java 代理 来检测用 Java 编写的演示应用程序。通过简单的配置,代理可以自动检测 Java 应用程序。相比之下,CloudFront 没有这样的自动工具可用。因此,我们在 亚马逊云科技 Lam bda 函数中构建与 OpenTelemetry 兼容的负载,并向从 Java 应用程序提取自动检测跟踪信息的同一 OpenTelemetry 收集器发出 HTTP POST 请求。

收集器用作收集、处理遥测数据并将其导出到您选择的追踪后端的通用门面。在这篇文章中,我们采用亚马逊 OpenSearch 服务作为追踪后端。目前,OpenTelemetry 格式无法直接提取到亚马逊 OpenSearch 服务,因此我们在两者之间使用 Data Prepper 来转换数据格式。

Figure 2: Trace data format conversion using Data Prepper

图 2:使用 Data Prepper 跟踪数据格式转换

安装

您可以按照关联的 Git 存储库 中指定的步骤在您的 亚马逊云科技 账户中安装相同的架构 。 简而言之,你必须将演示应用程序的 docker 镜像托管到 ECR 并运行存储库中提供的 Terraform 脚本。

草率排练

在本节中,我们将关注用户请求流程并研究跟踪的工作原理。以下子部分的顺序与解决方案概述图中的编号相匹配。

CloudFront 查看器请求

CloudFront 处于我们后端架构的最前沿。当 CloudFront 收到来自最终用户的请求时,如果已经定义了 CloudFront 查看器请求事件并将其与 CloudFront 分配相关联,则会触发该事件。这是跟踪的关键步骤,因为我们可以定义根跨度及其开始时间,并以请求标头的形式将其传播到源。

Figure 3: Concept of CloudFront Viewer Request Function and Viewer Response Function

图 3:CloudFront 查看器请求函数和查看器响应函数的概念

跟踪上下文(或跨度上下文)是有关跨度的元数据,例如跟踪 ID、跨度 ID 和采样标志。与面包屑一样,Trace Context 附加到请求标头,并将请求一起转发到后端服务。因此,后备服务可以创建子跨度并将其与父跨度关联。

CloudFront 查看器请求函数代码 执行以下 操作:

  • 在第 7-11 行中,我们生成根跨度的跟踪上下文。 我们使用由 CloudFront 生成的 requestId ,将 base64 的二进制块转换为十六进制字符串,因此我们的 trac eID 和 SpanID 与 b3 规范兼容。
  • 在第 14-16 行中, traceID SpanID 使用标头密钥 b3 附加到请求标头。 该标头将传播到 OpenTelemetry Java 代理。
  • 我们将采样率设置为 1 以进行演示。在生产中,您可以将速率设置在 0 到 1 之间,以提高性能。
  • 我们附加了另一个请求标头, 即跟踪开始时间 ,以记录根跨度的开始时间。查看器响应函数将其包含在根跨度数据中。

演示应用程序

您的请求由在 Amazon EKS 上运行的演示应用程序(后端 Java 应用程序)提供服务。OpenTelemetry Java 代理将每项应用程序事务记录为一组相关的跨度数据,并将这些数据转发给 OpenTelemetry Collector。

打开遥测 Java 代理

使用 OpenTelemetry,我们可以手动或自动对 Java 应用程序进行检测。在大多数情况下,使用自动检测足以满足跟踪目的。此外,通过使用 OpenTelemetry Java 代理,我们不需要向应用程序添加静态依赖关系,因为代理会在运行时插入字节码。因此,我们使用代理来检测演示应用程序。

为了启用 OpenTelemetry Java 代理,我们在运行应用程序 jar 文件时添加了一个 Java 选项:

java -javaagent:/path/to/aws-opentelemetry-agent.jar -jar app.jar

我们将代理配置作为环境变量注入:

  • OTEL_EXPORTER_OTLP_ENDPOINT :这是 OpenTelemetry Java 代理向其发送遥测数据的端点。在这里,我们将代理配置为通过 GRPC 协议(端口 4318)向 OpenTelemetry 收集器发送跟踪数据。
  • otel_traces_exporter= “OTLP” :代理以 OpenTelemetry 格式导出 跟踪数据。
  • otel_propagators= "b3" :代理使用 b3 规范来处理请求标头中的跟踪上下文。
  • otel_traces_sampler= “parentbased_always_OFF” :只有当前面的服务在开 启采样标志的情况下发送跟踪上下文时,代理才会生成跨度数据。

CloudFront 查看器响应

当 CloudFront 将响应返回给最终用户时,如果已经定义并与 CloudFront 分配相关联,则会触发 CloudFront 查看器响应事件。 在此步骤中,创建包含 CloudFront Requ estId 、跟踪开始时间、跟踪结束时间 和 b3 传播标 头的 Amazon CloudWatch 日志。

Figure 4: CloudWatch Log written by CloudFront Viewer Response Function

图 4:CloudFront 查看器响应函数编写的 CloudWatch 日志

CloudFront 查看器响应函数代码 执行以下 操作:

  • 在第 5-10 行中,我们使用键 跟踪采样率 解析标头值, 以决定是否将日志写入 CloudWatch。
  • 在第 8 行中,我们向 CloudWatch 写了一条日志。您可以扩展此概念并在日志中添加任意值以获得更好的可观测性。
  • 在第 9 行中,我们将查看器请求函数中生成的 b3 标头添加到响应标头中。

云观订阅筛选器

CloudWatch 订阅筛选器允许您将与给定筛选表达式相匹配的日志事件子集提供给其他服务,例如 Amazon Kinesis 流、 亚马逊 Kinesis Data Firehose 流或 Lambda 函数。在这篇文章中,我们使用了 Lambda 函数作为活动的目标服务。

为了从 CloudWatch 日志中筛选出不必要的日志项目,我们添加了一个订阅筛选器,如下所示。通过应用此过滤器,带 有 START 或 END 的行将被忽略,只有带有跟踪 开始 时间 、 跟踪 结束 时间 和 b3 标头的行才会被传递 到 Lambda 函数

Figure 5: CloudWatch Subscription Filter

图 5:CloudWatch 订阅筛选器

Lambda 跟踪处理器

收到来自 CloudWatch 订阅过滤器的 base64 编码和 gzip 压缩的日志事件后,名为 Lambda 跟踪处理器的 Lambda 函数会生成与 OpenTelemetry 兼容的负载并向 OpenTelemetry 收集器发出 HTTP POST 请求。

在下文中,我们将重点介绍 Lambda 跟踪处理器 代码的关键部分:

  • 在第 26-39 行中,我们解压缩事件数据,并使用从事件数据中检索到的信息填充兼容 OpenTelemetry 的有效负载。
  • 在第 41-51 行中,我们将有效载荷提交给 OpenTelemetry 收集器。
  • 我们使用服务名称属性标记根跨度数据(第 66-71 行)。
  • 在负载中,我们附加根跨度数据(第 96-99 行),包括跟踪 ID、跨度 ID 以及根跨度的开始和结束时间。
  • 我们将根跨度命名为 CloudFront 发行版的域名(第 100 行)。
  • 或者,我们可以将 CloudFront 请求 ID(第 103-108 行)作为附加属性添加到跨度中,用于调试。

打开遥测收集器

OpenTelemetry Collector 用作接收、处理和导出遥测数据的通用管道。收集器接收来自仪器库和代理的遥测数据,处理其他处理,例如批处理、重试和加密,并将数据转发到可观测性后端。尽管可以在没有收集器的情况下将遥测数据发送到后端,但建议在生产环境中使用收集器。

我们将收集器作为网关服务部署到 Amazon EKS 集群中,将跟踪数据集体发送到 Data Prepper,这是另一个将 OpenTelemetry 数据转换为亚马逊 OpenSearch Service 文档格式的数据管道。你可以参阅 GitHub 存储库中的详细 收集器配置

数据准备者

尽管 OpenTelemetry Collector 旨在支持多个可观测性后端,但目前,它无法直接将数据导出到亚马逊 OpenSearch Service。 Data Prepper 是在亚马逊 OpenSearch Service 项目下开发的另一个遥测数据管道。我们使用 Data Prepper 将从 OpenTelemetry Collector 导出的数据转换为兼容亚马逊 OpenSearch 服务的格式。

亚马逊开放搜索——追踪分析

所有追踪数据最终都保存到亚马逊 OpenSearch 服务。使用 亚马逊 OpenSearch 服务 跟踪分析 ,我们可以可视化请求流并分析任何性能问题。为了探索示例跟踪,我们首先使用 CURL 向我们的后端发送 API 请求(运行 terraform 输出 命令以找到演示应用程序端点 URL):

curl --head {demo-app_endpoint_url}

在终端输出中,找到 b3 响应头。 b3 标头的第一部分由连字符(“-”)分隔,是与我们的请求相关的跟踪 ID。

Figure 6: Demo App API call terminal output

图 6:演示应用程序 API 调用终端输出

接下来,让我们登录亚马逊 OpenSearch Service 来查看跟踪数据。运行 terraform 输出 命令找到亚马逊 OpenSearch Service Kibana 控制面板网址并登录。有关登录信息,您可以参阅 Terraform 变量文件

登录后,导航到跟踪分析 > 跟踪。在那里你可以找到与我们发出的请求相关的追踪编号。如果没有,则可能需要调整右上角的查询时间范围。在列表中选择跟踪 ID 以查看跟踪详情。

Figure 7: Trace List in the OpenSearch Trace Analytics Page

图 7:OpenSearch 跟踪分析页面中的跟踪列表

这是追踪的详情页面。从中间的饼图中,您可以发现跟踪数据是从 CloudFront 和演示应用程序收集的。饼图的右边是轨迹中跨度的树视图。它以图形方式显示跨度的时间顺序(垂直)和每个跨度的持续时间(水平)。

Figure 8: Trace Details in the OpenSearch Trace Analytics

图 8:OpenSearch 追踪分析中的追踪详情

结论

我们在 亚马逊云科技 上构建了一个示例后端系统,并表明您可以从 CloudFront 开始跟踪用户请求。此外,您可以使用跟踪数据来更好地了解分布式系统并识别性能瓶颈。

通过利用 OpenTelemetry 的兼容性,你可以编写 CloudFront 函数来分析 CloudFront。OpenTelemetry 是一个供应商中立的开源可观察性框架。它试图标准化遥测数据格式和收集过程。它正在成为行业标准,并已得到包括亚马逊云科技在内的多家供应商的支持。

如果您尚未这样做,我们建议您 查看 OpenTelemet ry 并尝试使用它来增强应用程序的可观测性。

Wooyoung Jung

郑宇英

Wooyoung Jung 是一名在 亚马逊云科技 专业服务部门工作的应用程序架构师。他对软件设计和企业架构非常感兴趣。他主要帮助企业客户实现应用程序现代化。

Eunju Rho

Eunju Rho

Eunju 是 亚马逊云科技 专业服务的应用程序开发人员。她与 亚马逊云科技 客户合作,在云中构建客户应用程序并对其进行现代化改造。

Sean Lee

肖恩李

Sean Lee 是亚马逊网络服务的高级应用程序架构师。他的重点领域包括容器、无服务器和 DevOps。他热衷于帮助客户使用 亚马逊云科技 服务构建云原生应用程序。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。