无服务器功能的采用在企业组织内达到了创纪录的水平。有趣的是,鉴于越来越多的采用和兴趣,许多监控解决方案孤立了在这些环境中执行的代码的性能,或者仅提供有关执行的基本指标。为了了解应用程序的性能,我想知道存在哪些瓶颈、时间花在哪里以及满足请求所涉及的每个系统的当前状态。虽然指标、日志和分段堆栈跟踪很有帮助,但更具凝聚力的性能故事仍然是理解应用程序的最有用的方法,并且 应该 可以使用现有技术来实现。
在这篇文章中,我将探讨如何使用 OpenTracing 来检测在本地容器中运行的 Express 应用程序以及在 Lambda 上运行的函数,从而实现连贯的性能故事。对于可视化和分析,我将在本示例中使用 LightStep [ x ]PM,尽管您可以选择其他 OpenTracing 后端,例如 Jaeger。
系统性能正是其各个部分的总和
在我们开始之前,有必要检查一下此练习的目的。正如我所提到的,几乎每个 FaaS(功能即服务)提供商都以合理的价格提供了对各个功能性能的一定程度的可见性。
最新的 DZone 参考卡
移动数据库要点
调用计数、错误率、日志,甚至堆栈跟踪触手可及,这非常引人注目。更引人注目的是无需 在实际开发工作之外做太多工作即可获取此信息。当表演数据按演员分段时,拼凑出一个有凝聚力的故事是一件令人沮丧的事情。每当我从事一个项目并试图量化该工作的价值时,我往往会想:“那又怎样,谁在乎呢?” 或者, 我通过这项工作、产品或技术到底创造了什么价值?
监控的价值是通过所提供的独特数据、正在解决的问题以及它如何到达需要它的人手中来衡量的。虽然指标和单独的堆栈跟踪适用于许多用例,但我创建此示例是因为,作为编写新功能、重构现有代码或只是保持正常状态的开发人员,您可能不得不依赖于您无法控制的系统和服务。在这些情况下,我认为分布式跟踪是完成这项工作的最佳工具。
你好,开放追踪
OpenTracing 是一个供应商中立的接口,它定义了如何测量基础设施中任何单个操作或组件的性能,以及如何将这些单独的部分连接在一起形成一个有凝聚力的端到端性能故事。重要的是, 这样做所需的数据 定义明确且非常简单:启动和停止时间戳、服务和操作名称以及通用事务 ID 基本上就是您开始所需的全部内容。后端通常负责将相关操作“粘合”在一起形成单个跟踪,因此开销可以非常小。
OpenTracing 的轻量级数据模型使其非常适合测量临时架构组件的性能,包括容器和无服务器功能。我们需要三样东西:OpenTracing 数据、将该数据传输到后端的方法,当然还有后端本身。
开放追踪数据
OpenTracing 定义了每种语言所需的确切 API 调用,以提取必要的信息并将端到端跟踪组合在一起。目的是在整个环境中进行这些调用,然后让您所需的客户端库(接收 OpenTracing 数据并将其发送到后端的库)通过将自身建立为仪器的全局目标来接收结果数据。这意味着您可以在代码中准确定义要测量的内容。更重要的是,由于 OpenTracing 是一个开放标准,它被库和基础设施开发人员广泛采用,并且许多流行的框架和工具都内置了 OpenTracing 工具。
在此示例中,我们不会利用任何社区驱动的插件和工具。相反,我们将亲自动手来明确演示该技术的工作原理。我们将从后端开始。
关于 SpanContext 的简要说明
正如我所提到的,OpenTracing 需要在进行每次测量时提供一个通用事务 ID。这是使用称为 SpanContext 的对象在整个系统中捆绑和传输的。它可以包含在许多载体中,例如 HTTP 标头、文本映射和二进制 blob,并以适合您的服务的任何格式进行传输。在此示例中,由于这是一个 HTTP 请求,我们将把 SpanContext 注入到 HTTP 标头中。
后端仪表
首先,我们将初始化 客户端库 并将其指定为全局跟踪器,这使其成为整个应用程序中发出的任何 OpenTracing 数据的目的地。
正如您所看到的,我在这里创建了一条路由,它允许我们指示 Express 向我们的 Lambda 函数发送可变数量的请求(作为查询参数传递)。我在上面的代码中留下了评论,但这里的主要要点和步骤是:
调用路由时启动父跨度。这为我们的跟踪层次结构奠定了基础,我们将在下一步中使用它。
对于每个生成的 Lambda 函数,我们希望创建一个子范围。在 OpenTracing 中,每个跨度都有自己的 ID,该 ID 与持久事务 ID 一起包含在 SpanContext 中。这意味着每个子跨度都有自己的 SpanContext,需要将其传递到系统中的下一跳。
将 SpanContext 注入请求标头并将其附加到我们的 Lambda POST 请求。
如果请求中存在错误,我们会将错误与布尔 KV 对一起附加,该布尔 KV 对告诉我们的后端活动跨度上存在错误。这在像 LightStep [ x ]PM这样的系统中变得非常有用,其中错误率是自动计算的,并且可以用作警报和分析的基础。
在发出所有 Lambda 请求后结束父级跨度,并在从 AWS API Gateway 收到 200 后结束每个子级跨度。在 Lambda 请求离开我们的应用程序后,我们将在此处结束父跨度,但我们不会等待响应。这是一个偏好问题,可以根据您的需要进行修改。
功能仪表
在检测任何无服务器功能时,我们希望确保尽可能提高性能。大多数提供商都会考虑执行时间,因此监控期间增加的任何开销都会产生与之相关的直接成本。
在 Lambda 上跟踪 HTTP 请求时需要执行一个额外步骤:在事件中公开 HTTP 标头。幸运的是, Ken Brodhagen 的这篇精彩博客文章 解释了如何做到这一点。将映射模板添加到 API 网关后,“event.headers”将包含 HTTP 标头,允许您提取 SpanContext。