ShadowReader:用于重放生产流量的无服务器负载测试

这个开源工具重现无服务器生产条件,以查明在 QA 环境中不可见的内存泄漏和其他错误的原因。
161 位读者喜欢这篇文章。
Testing certificate chains with a 34-line Go program

carrotmadman6。由 Opensource.com 修改。CC BY-SA 2.0

虽然负载测试变得越来越容易,但配置能够忠实地重现生产条件的负载测试仍然很困难。一个好的负载测试必须使用一组代表生产流量的 URL,并达到模拟真实用户的请求速率。即使执行分布式负载测试也需要维护大量的服务器。

ShadowReader 旨在解决这些问题。它直接从生产日志中收集 URL 和请求速率,并使用 AWS Lambda 重放它们。由于是无服务器的,因此它比传统的分布式负载测试更具成本效益和性能;在实践中,它已经扩展到每分钟超过 50,000 个请求。

在 Edmunds,我们已经能够利用这些功能来解决问题,例如仅在生产环境中发生的 Node.js 内存泄漏,方法是在我们的 QA 环境中重现相同的条件。我们还每天使用它为预生产 Canary 部署生成负载。

我们在 Node.js 应用程序中遇到的内存泄漏问题使我们的工程团队感到困惑;因为它只发生在我们的生产环境中;在我们引入 ShadowReader 将生产流量重放到 QA 之前,我们无法在 QA 中重现它。

事件

在 2017 年圣诞节前夕,我们遇到了一个事件,整个网站的响应时间都出现了跳跃式增长,错误率增加了两倍,影响了我们网站的许多用户。

Christmas Eve 2017 incident

Christmas Eve 2017 incident

事件期间的监控帮助我们快速识别和解决问题,但我们仍然需要了解根本原因。

在 Edmunds,我们利用强大的持续交付 (CD) 管道,每天多次将新更新发布到生产环境。我们还动态扩展我们的应用程序以适应高峰流量并缩减规模以节省成本。不幸的是,这产生了掩盖内存泄漏的副作用。

在我们的调查中,我们发现内存泄漏已经存在了数周,自 12 月初以来。内存使用率会攀升至 60%,同时第 99 百分位响应时间缓慢增加。

在我们的 CD 管道和自动扩展事件之间,长时间运行的容器经常被关闭并被更新的容器替换。这无意中掩盖了内存泄漏,直到 12 月,当我们决定停止发布软件以确保假期期间的稳定性时,内存泄漏才被发现。

Slow increase in 99th percentile response time

我们的 CD 管道

概览,Edmunds 的 CD 管道如下所示

  1. 单元测试
  2. 为应用程序构建 Docker 镜像
  3. 集成测试
  4. 负载测试/性能测试
  5. Canary 发布

该解决方案是完全自动化的,不需要手动切换。最后一步是直接将 Canary 部署到实时网站中,这使我们能够每天多次发布。

对于我们的负载测试,我们利用了构建在 JMeter 之上的自定义工具。它从生产 URL 中获取随机样本,并且可以模拟各种百分比的流量。然而,不幸的是,我们的负载测试无法在我们的任何预生产环境中重现内存泄漏。

解决内存泄漏

在查看 QA 中的内存模式时,我们注意到存在非常健康的模式。我们最初的假设是,我们在 QA 中的 JMeter 负载测试无法以允许我们预测应用程序性能的方式模拟生产流量。

虽然负载测试从生产 URL 中获取样本,但它无法精确地模拟客户使用的 URL 以及调用的确切频率(即突发速率)。

我们的第一步是在 QA 中重现问题。我们使用了一个名为 ShadowReader 的新工具,该项目是从我们的黑客马拉松演变而来的。虽然我们考虑的许多项目都以产品为中心,但这是唯一一个以运营为中心的项目。它是一个在 AWS Lambda 上运行的负载测试工具,可以针对我们的 QA 环境重放生产流量和使用模式。

它返回的结果是立竿见影的

QA results in ShadowReader

在知道我们可以在 QA 中重现问题后,我们采取了额外的步骤,将 ShadowReader 指向我们的本地环境,因为这使我们能够触发 Node.js 堆转储。在分析转储的内容后,很明显内存泄漏来自两个过大的对象,这两个对象仅包含字符串。在转储快照时,这些对象包含 373MB 和 63MB 的字符串!

Heap dumps show source of memory leak

我们发现这两个对象都是临时查找缓存,其中包含要在客户端使用的元数据。这两个缓存都不打算持久保存在服务器端。用户的浏览器仅缓存了自己的元数据,但在服务器端,它缓存了所有用户的元数据。这就是为什么我们无法通过综合测试重现泄漏的原因。综合测试总是导致服务器端缓存中相同的固定元数据集。只有当我们有足够数量的来自各种用户的唯一元数据生成时,泄漏才会浮出水面。

一旦我们确定了问题,我们就能够删除我们在堆转储中观察到的大型缓存。从那时起,我们对应用程序进行了检测,开始收集指标,这些指标可以帮助更快地检测到此类问题。

Collecting metrics

在 QA 中进行修复后,我们看到内存使用量是恒定的,并且泄漏被堵住了。

Graph showing memory leak fixed

什么是 ShadowReader?

ShadowReader 是一个无服务器负载测试框架,由 AWS Lambda 和 S3 提供支持,用于重放生产流量。它通过以与实时网站相同的速率重放来自生产环境的 URL 来模拟真实用户流量。我们很高兴地宣布,经过数月的内部使用,我们已将其作为开源发布!

功能

  • ShadowReader 通过重放用户请求(URL)来模拟真实用户流量。它还可以重放某些标头,例如 True-Client-IP 和 User-Agent,以及 URL。
  • 与在大量服务器上运行的传统分布式负载测试相比,它在成本和性能方面都更有效。管理用于分布式负载测试的大量服务器每月可能花费 1,000 美元或更多;使用无服务器堆栈,通过按需配置计算资源,可以将成本降低到每月 100 美元。
  • 我们已将其扩展到每分钟 50,000 个请求,但它应该能够处理每分钟超过 100,000 个请求。
  • 与传统的负载测试工具不同,新的负载测试可以立即启动和停止,而传统的负载测试工具可能需要几分钟才能生成测试计划并将测试数据分发到负载测试服务器。
  • 它可以按百分比值增加或减少流量,以充当更传统的负载测试。
  • 它的插件系统使您能够切换插件以更改其行为。例如,您可以从过去重放(即重放过去的请求)切换到实时重放(即在请求进入时重放请求)。
  • 目前,它可以重放来自应用程序负载均衡器和经典负载均衡器弹性负载均衡器 (ELB) 的日志,并且即将支持其他负载均衡器。

工作原理

ShadowReader 由四个不同的 Lambda 组成:Parser、Orchestrator、Master 和 Worker。

ShadowReader architecture

当用户访问网站时,负载均衡器(在本例中为 ELB)通常会路由请求。当 ELB 路由请求时,它将记录事件并将其发送到 S3。

接下来,ShadowReader 通过 CloudWatch 事件每分钟触发一次 Parser Lambda,该事件解析 S3 上该分钟的最新访问(ELB)日志,然后将解析后的 URL 发送到另一个 S3 存储桶。

在系统的另一侧,ShadowReader 也每分钟触发一个 Orchestrator lambda。此 Lambda 保存系统的配置和状态。

然后,Orchestrator 调用 Master Lambda 函数。Master 从 Orchestrator 接收有关要重放的时间片的信息,并从解析后的 URL 的 S3 存储桶(由 Parser 存放在那里)下载相应的数据。

Master Lambda 将负载测试 URL 分成更小的批次,然后调用每个批次并将其传递给 Worker Lambda。如果必须发送 800 个请求,则将调用八个 Worker Lambda,每个 Lambda 处理 100 个 URL。

最后,Worker 接收从 Master 传递的 URL,并开始对选定的测试环境进行负载测试。

更大的图景

随着我们从稳态应用程序大小调整转向按需模型,在负载测试无服务器基础设施中可重现性的挑战变得越来越重要。虽然 ShadowReader 的设计和使用考虑了 Edmunds 的基础设施,但任何利用 ELB 的应用程序都可以充分利用它。很快,它将支持重放生成流量日志的任何服务的流量。

随着项目的推进,我们希望看到它发展为与下一代无服务器运行时(例如 Knative)兼容。随着无服务器变得越来越普遍,我们也希望看到其他开源社区为他们的基础设施构建类似的工具链。

入门指南

如果您想试用 ShadowReader,请查看 GitHub 仓库。README 包含操作指南和一个包含所有功能的 演示,该演示将部署所有必要的资源,以便在您的 AWS 账户中试用实时重放。

我们很乐意听取您的想法,并欢迎贡献。请参阅 贡献指南 以开始使用!


本文基于 “我们如何通过使用 ShadowReader 将生产流量重放到 QA 来修复 Node.js 内存泄漏”,该文章在 Edmunds Tech Blog 上发布,并得到了 Carlos Macasaet、Sharath Gowda 和 Joey Davis 的帮助。Yuki Sawa 还在 as ShadowReader—用于重放生产流量的无服务器负载测试 在 (SCaLE 17x) 3 月 7 日至 10 日在加利福尼亚州帕萨迪纳举行会议上介绍了该内容。

标签
User profile image.
Yuki 是 Edmunds 云基础设施团队的软件工程师,他在该团队中在 AWS 平台上构建高度弹性和高性能的系统。在那里,他领导着开源项目 ShadowReader,这是一个每天在 Edmunds 使用的无服务器负载测试框架。在他的日常工作中,他使用 Docker、Kubernetes、Spinnaker 和 Serverless 等技术。

2 条评论

我肯定会删除 master 并将该段代码放在 orchestrator 中。然后将生成的所有作业(块)放入 SQS 中,并让 worker 监听消息。这样你就可以更轻松地扩展它。

谢谢,这是一个非常有趣的评论。这篇文章中没有概述,但在 Edmunds,每个被测试的应用程序都会调用一个 Master lambda。因此,可能会有一个 App1 Master 和 App2 Master 并行运行,每个 Master 都运行自己的 Worker lambda,其中包含不同的 URL 集。当对整个 Edmunds 网站进行负载测试时,Orchestrator 会并发调用 30 多个 Master。希望这能更清楚地说明我们为什么采用这种方法。

回复 I would definitely remove the,作者为 Elvis Ligu (未验证)

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.