RubyGems 导航菜单

博客

返回到博客文章

精简我们的堆栈

你好,Ruby 社区:

今天,我们要宣布一个好消息:我们无需再使用 Redis 来运行 RubyGems.org,并且我们正在移除 Nginx SPOF(单点故障)。我们已安装了一套全新的下载统计系统,并且关闭了我们的 Redis 实例。

Redis 不好吗?

如果使用得当,它一点也不差!许多公司都在使用 Redis,并且它还有许多有效的用例。Redis 的主要用例之一是将它用作后台任务的队列。我们使用 PostgreSQL 和 DelayedJob 来处理后台任务,所以我们不需要 Redis 来做这个。我们的问题来自我们使用它以及存储数据的方式。我们以永久非过期方式存储所有数据,并且存储和内存都增长了不少。我们在使用 Redis 时遇到的主要问题是将数据加载到运行实例所需的内存。这是资源密集且耗时的。如果有一个实例因任何原因宕机,它需要重新加载所有的内容到内存中,因此要使其再次可用需要很多分钟的时间。我们的部分 Redis 故障导致我们花了大约 45 分钟才恢复它的运行。在 Redis 中没有存储大量数据时(比如后台任务),这通常不是一个问题。

我们之前的统计架构

我们主要使用 Redis 来进行宝石下载计数。这个架构多年来一直是这样的:

  1. 每次下载一个宝石时,请求会首先通过我们的 Nginx 负载均衡器。
  2. 在将用户重定向到我们的宝石 CDN 之前,Nginx 会向一个内部服务发送一个辅助的 http 请求,其中包含宝石信息。
  3. 这个内部服务是一个小型 C 后端,用于解析请求以及增加 Redis 中的计数器。
  4. 显示在各种 RubyGems.org 页面和 API 响应中的计数器正是来自 Redis。

正如你所想的那样,RubyGems.org 收到了很多下载请求。我们希望直接从我们的 CDN 提供下载,但我们需要请求先击中 Nginx 才能跟踪这些下载。此外,如果这个架构的任何部分宕机,我们将会永久丢失下载计数。

我们现在使用什么

我们现在可以通过我们的 CDN 提供商 Fastly 直接提供所有宝石下载。以下是我们新的架构:

  1. 宝石下载请求击中 Fastly,在这里宝石可能已经根据地理位置缓存,并且离用户很近。
  2. Fastly 每五分钟生成一个日志文件,并将其推送到 S3。
  3. S3 向队列推送 SQS 通知消息。
  4. RubyGems.org Rails 应用程序使用这些 SQS 消息并计划一个后台作业来处理每个新的 S3 文件。
  5. DelayedJob 运行后台作业并更新 PostgreSQL 中的计数器。
  6. Rails 应用程序现在可以使用直接来自 PostgreSQL 数据库的计数器。

新架构的缺点

  • 计数器每五分钟仅更新一次。不过,这是一个小小的代价,它允许我们执行更多的缓存。

新架构的优点

  • 我们可直接从边缘位置的 CDN 为 .gem 下载提供服务。
  • 永久数据存储的数量从 2 个减少至 1 个,这对我们的服务弹性来说是一项巨大的进步。
  • gem 下载不再需要 Nginx,从而消除了 SPOF。
  • 我们的堆栈变得更加简化。
  • 更小的停机窗口。
  • 更简单的本地开发设置。
  • 如果需要,我们可以暂停后台处理或甚至重新统计下载的数量。

未来计划

我们在撰写此文时仍通过 Nginx 为 gem 提供服务,并重定向到 Fastly。随着我们完成向 Fastly 的完全过渡,这将在近期内得到更改。期待另一篇博文来解释这种过渡。

特别感谢

Aaron SuggsDavid RadcliffeArthur Neves,感谢他们在这个项目中辛勤工作。