如果说 Redis 有什么为人所知,那就是速度;它被认为是现代 K/V 存储中最具性能的。Redis 的几乎每个设计和实现方面都强调最大效率,并且以最佳性能为目标。
然而,有些方面可能会无意中导致 Redis 服务器的性能远低于最佳状态。其中一个方面是看似有用的功能,即在单个 Redis 实例上管理多个数据库(而不是每个实例一个数据库的专用方法)。过去 Eli、kenn、Chris Laskey、matteo 等人已经在 Stack Overflow、博客和 Redis 群组中讨论过这个话题。
理论
与传统 RDBMS 的模式非常相似,Redis 的数据库由 Redis 服务器的单个实例管理,但在逻辑上保持分离。让单个 Redis 实例管理多个数据库的主要好处是减少了管理开销。单个应用程序通常会同时使用多个数据库(例如,会话、排名、计数器……),而每个环境(开发、测试、暂存、生产……)都需要这些数据库。通过让单个 Redis 实例管理多个(最多 16 个)数据库,可以降低实例(以及可能的服务器)的总数,从而减少管理它们所需的工作量。
使用单个实例来管理多个数据库(又名共享实例)以减少管理的论点完全合理,因此应用程序开发人员通常会临时采用这种方法。然而,事物的本质是,临时的会变成永久的。因此,共享实例部署选择被延续下来,有时甚至进入生产环境。而这通常是在性能问题浮出水面的时候。
由于 Redis 的架构,共享实例最终会表现得不尽人意。为了实现极快的速度,每个 Redis 实例都使用(几乎)单线程来实现,以消除上下文切换的工作量、取消阻塞并提供简单的序列化。由于共享实例使用单线程,因此该线程可能会因针对特定数据库执行的操作而变慢甚至被阻塞,从而影响其他数据库。虽然在开发和测试中几乎难以察觉,但如果在生产环境中遇到这种情况,可能会造成灾难性的后果。
证明
我们着手通过基准测试来证明这一点。我们在 us-east-1 中设置了一个 m2.4xlarge AWS 实例作为我们的客户端应用程序,并使用它来运行我们自己开发的基准测试工具(可从我们的 github 帐户
here 获取)。基准测试工具的每次运行都包括通过启动 4 个线程并让每个线程打开 25 个连接来执行 10000 个 SET 和 GET 操作(1:1 的比例)。我们让该工具对每次运行进行 10 次迭代,以收集有意义的总体平均值。对于那些希望重现我们的结果的人,这里是运行基准测试工具的语法
memtier_benchmark -s <host> -p <port> -P redis -t 4 -n 10000 –ratio 1:1 -c 25 -x 10 -d 100 –key-pattern S:S
我们针对两个 Redis 实例运行了基准测试,每个实例运行两次。第一个实例是在 m1.xlarge AWS 实例上运行的标准 Redis 服务器,第二个实例是我们自己的 Redis Cloud 服务中新配置的资源。两台服务器都使用 Ubuntu v12.04 和 Redis v2.6.14(我们将在几周内将 v2.6.14 推广到我们的生产服务)。
针对每个实例的第一次运行旨在以专用模式对该实例的性能进行基准测试,因此只有基准测试工具使用它。在第二次运行中,我们模拟了一个共享实例场景,因此我们创建了另一个数据库
1,并在基准测试运行的同时,在一个无限循环中对其执行资源密集型的
ZINTERSTORE 操作。
以下图表清楚地显示了我们的小循环对基准测试结果的影响,共享实例的性能指标下降了一个数量级。每个实例的吞吐量(以其处理的每秒平均请求数衡量)从几乎 35K 降至略高于 3.5K 个请求每秒
每秒请求数图表
每个实例的延迟(以平均响应时间(毫秒)衡量)也受到了影响——从略低于 3 毫秒增加到几乎 28 毫秒
平均响应时间图表
最后但并非最不重要的是,代表延迟分布曲线尾部的最高 95% 的请求的响应时间。虽然两个专用实例都在同一邻域,但共享实例远远超出了它们的范围
第 95 个百分位数的响应时间图表
不可避免的结论
Redis 是一项了不起的技术,具有丰富的功能和令人印象深刻的功能。像任何工具一样,它可能会被滥用并产生不良结果。使用共享 Redis 实例最初可能会节省大量开销,但在生产中使用它们通常被认为是一个坏主意。尽管它需要增加工作量,但我们建议仅将专用 Redis 实例用于实际目的。这些实例不仅避免了数据库间的阻塞,而且还允许为每个数据库配置不同的数据持久性和驱逐策略。此外,Redis 可能会逐渐放弃共享实例,因此无论如何,停止使用它们都是一个好主意。
1 实际上,我们的 Redis Cloud 服务中的每个资源都是一个专用实例。因此,第二次 Redis Cloud 基准测试运行是针对两个独立的资源(数据库)执行的,并且显示的结果与针对该服务的第一次基准测试运行的结果相同