最初发布于 bleacherreport.com
我们的 API 服务使用 Redis 作为其缓存层。 Redis 集操作对于我们的 API 服务中所需的逻辑非常有用。 不幸的是,我们在扩展 Redis 方面遇到了一些问题。 Redis 是一个单线程服务器,它使用基于事件的范例读取传入的连接,因此仅使用 1 个 CPU 核心。 因此,您可以垂直扩展 Redis,但水平扩展 Redis 非常具有挑战性。 当我们的应用程序调用更重的 zset 和 zunionstore 操作时,我们就会看到这一点。 Redis 达到 CPU 限制,并且被固定在 100%。
我们还看到了 Redis 将内存中的数据快照到磁盘的方式存在问题。 Redis 会分叉另一个进程来保存数据,该进程会使 Redis 的 RAM 占用量翻倍。 一旦 Redis 耗尽了盒子上的内存,它就会变得非常慢。 这有效地将您可以在盒子上使用的内存减少到实际可用总内存的一半。 在我们的例子中,我们使用 Redis 作为缓存,因此我们只是禁用了保存,以便我们可以使用盒子上的所有内存,并且我们一直在垂直扩展。 但是,垂直扩展只能让你走这么远。 我们目前的瓶颈是我们正在接近可用 CPU 的上限。
我们想尝试 Redis 集群,但开源版本仍在开发中。 Redis 是开源 Redis 项目的主要贡献者之一,他们的平台上已经可以进行集群。 Redis 经过精心设计,可以自动无缝地扩展。 Redis 数据库将在单个分片上增加容量,并且在需要时自动开始跨多个分片进行集群。 所有这些都在后台透明地发生。 客户只需要管理一个简单的单个端点。
除了基本的健全性测试和功能测试之外,我们还需要定量测量和性能指标来证明我们迁移的合理性。
我们使用 em-proxy 在迁移服务器到新集群时进行蓝绿流量。 这使我们可以将一部分流量代理到 Redis,对其进行测试,并对包含的暴露进行更改做出反应。
那天晚上在 Google 上搜索了几次之后,我遇到了 它,然后我在当晚使用单个实例进行了一些测试。 然后在第二天晚上,我创建了一个额外的测试集群,这大约花了 5 分钟,然后将来自实时生产集群的所有流量定向到测试集群,并让它运行一夜和第二天。 这种技术强大的地方在于我们不是用输入基准数据进行猜测,而是实际上使用实时生产流量。 最重要的是,我们可以实时比较 New Relic 数据集。
结果令人难以置信。
左图基于我们在内部维护的 Redis 服务器。 右图是连接到 Redis 的测试集群。 集群之间唯一的区别是一个使用开源 Redis 服务器,另一个使用 Redis。 使用标准开源 Redis 服务器,我们看到响应时间出现高达 700 毫秒的间歇性峰值,平均为 435 毫秒; 一切都乱七八糟的。 Redis 使我们的响应时间始终如一且平稳,平均为 55 毫秒! 无论 Redis 正在施展什么巫术黑魔法,它显然都在起作用。
在我们的测试期间,我们发现 Redis 禁用了某些 Redis 命令,因此我们需要对我们的 API 代码进行一些更改。
例如,Redis 禁用了 object
命令。
下一个错误是由于 Redis 正在分片,但我们的应用程序没有配备来处理它。
要解决此问题,您需要命名 Redis 键,以便 Redis 可以管理数据分片。 键需要用花括号命名,例如 hello{dynamic}world
。 因此,以下键映射到单独的分片
此处更详细地解释了这一点: /kb/redis-cloud-cluster。 我们最终部署到单个分片,这与我们之前的环境完全相同,并且将在以后返回到分片。
这种测试方法非常强大。 我们发现了很多问题,我们能够在实际在生产中推出 Redis 之前 解决这些问题。 如果我们改为将所有流量转移到 Redis,我们将处于救火状态,并且可能会回滚,而没有意识到 Redis 提供的巨大的性能机会。
Redis 很快! 如果您仔细阅读,您可能已经意识到关键。 我们从 Redis 获得了这种性能提升,甚至没有进行分片。 我们还有更多后续工作要做,包括分片,这应该会更大幅度地提高我们的性能。 如果您正在使用 Redis 并且在将其扩展到单个 CPU 之外或受到内存限制时遇到问题,那么 Redis 是一个不错的选择。