Memcached 与 Redis?

我们正在将带Redis服务器的 Ruby Web 应用程序用于缓存。有没有要测试Memcached 的地方呢?

什么会给我们带来更好的性能? Redis 和 Memcached 之间有什么优缺点?

要考虑的要点:

  • 读 / 写速度。
  • 内存使用情况。
  • 磁盘 I / O 转储。
  • 缩放比例。

答案

摘要(TL; DR)

2017 年 6 月 3 日更新

与 memcached 相比,Redis 功能更强大,更受欢迎并且得到更好的支持。 Memcached 只能做 Redis 可以做的一小部分。即使 Redis 的功能重叠,Redis 也更好。

对于任何新内容,请使用 Redis。

Memcached 与 Redis:直接比较

两种工具都是功能强大,快速的内存中数据存储,可用作缓存。两者都可以通过缓存数据库结果,HTML 片段或其他可能产生成本很高的内容来帮助加快应用程序的速度。

要考虑的要点

当用于同一事物时,以下是它们如何使用原始问题的 “要考虑的要点” 进行比较:

  • 读 / 写速度 :两者都非常快。基准测试因工作负载,版本和许多其他因素而异,但通常显示 redis 与 memcached 一样快或几乎一样快。我建议使用 redis,但不是因为 memcached 速度慢。不是。
  • 内存使用 :Redis 更好。
    • memcached:您指定高速缓存大小,并且在插入项目时,守护程序会迅速增长到略大于该大小。除了重新启动 memcached 之外,从来没有真正的方法可以回收任何空间。您所有的密钥都可能过期,您可以刷新数据库,并且该数据库仍将使用您为其配置的全部 RAM。
    • redis:设置最大大小由您决定。 Redis 将永远不会使用过多的内存,并将为您提供不再使用的内存。
    • 我将 100,000 个〜2KB 字符串(〜200MB)的随机句子存储到了两者中。 Memcached RAM 使用量增加到约 225MB。 Redis RAM 使用量增加到〜228MB。刷新两次后,redis 降至〜29MB,memcached 保持在〜225MB。它们在存储数据方面同样有效,但是只有一个能够回收数据。
  • 磁盘 I / O 转储 :Redis 显然是赢家,因为它默认情况下会这样做,并且具有非常可配置的持久性。没有第 3 方工具,Memcached 没有任何机制可以转储到磁盘。
  • 可扩展性 :在需要多个实例作为缓存之前,两者都为您提供了大量的净空。 Redis 包含的工具可帮助您超越此范围,而 memcached 则不会。

记忆快取

Memcached 是一个简单的易失性缓存服务器。它允许您存储键 / 值对,其中值限制为最大 1MB 的字符串。

擅长此事,但仅此而已。您可以通过它们的键以极高的速度访问这些值,这通常会使可用的网络或什至是内存带宽饱和。

重新启动内存缓存后,您的数据不见了。这对于缓存很好。您不应该在其中存储任何重要内容。

如果您需要高性能或高可用性,则可以使用第三方工具,产品和服务。

Redis

Redis 可以完成与 memcached 相同的工作,并且可以做得更好。

Redis 也可以充当缓存 。它也可以存储键 / 值对。在 redis 中,它们甚至可以达到 512MB。

您可以关闭持久性,并且在重新启动时也很可能会丢失数据。如果您希望缓存能够继续运行,那么重新启动也可以。实际上,这是默认设置。

它也非常快,通常受网络或内存带宽的限制。

如果一个 redis / memcached 实例的性能不足以处理您的工作负载,那么 redis 是不二之选。 Redis 包括集群支持,并附带了 “在盒子里” 的高可用性工具( redis-sentinel )。在过去的几年中,redis 也已成为第三方工具的明确领导者。 Redis Labs,Amazon 等公司提供许多有用的 Redis 工具和服务。 Redis 周围的生态系统更大。现在,大规模部署的数量可能会大于内存缓存的数量。

Redis 超集

Redis 不仅仅是一个缓存。它是一个内存中的数据结构服务器。在下面,您将快速概览 Redis 可以做的事情,而不仅仅是像 memcached 这样的简单键 / 值缓存。 Redis 的大多数功能都是 memcached 无法做到的。

文献资料

Redis 的文档比 memcached 的文档更好。尽管这可能是主观的,但它似乎一直在越来越真实。

redis.io是一个很棒的易于导航的资源。它使您可以在浏览器中尝试 redis,甚至还可以通过文档中的每个命令为您提供实时的交互式示例。

现在,redis 的堆栈溢出结果是内存缓存的 2 倍。是 Google 结果的 2 倍。提供更多语言的更易于访问的示例。更积极的发展。更积极的客户开发。这些度量可能并没有太大的意义,但结合起来可以清楚地看到,有关 Redis 的支持和文档越来越多,而且是最新的。

坚持不懈

默认情况下,redis 使用称为快照的机制将数据持久保存到磁盘。如果您有足够的可用 RAM,则可以将所有数据写入磁盘,而性能几乎不会降低。它几乎是免费的!

在快照模式下,突然崩溃可能会导致少量数据丢失。如果您绝对需要确保没有任何数据丢失,请放心,redis 也使用 AOF(仅附加文件)模式支持您。在这种持久模式下,数据可以在写入时同步到磁盘。这样可以将最大写入吞吐量降低到磁盘可以写入的速度,但是仍然应该非常快。

如果需要,有许多配置选项可以微调持久性,但是默认设置非常明智。这些选项使将 Redis 设置为安全,冗余的数据存储位置变得容易。这是一个真实的数据库。

许多数据类型

Memcached 仅限于字符串,但是 Redis 是一个数据结构服务器,可以提供许多不同的数据类型。它还提供了充分利用这些数据类型所需的命令。

字符串( 命令

简单文本或二进制值,最大可为 512MB。这是唯一的数据类型 redis 和 memcached 共享,尽管 memcached 字符串限制为 1MB。

Redis 通过提供用于按位操作,位级别操作,浮点增量 / 减量支持,范围查询和多键操作的命令,为您提供了更多利用此数据类型的工具。 Memcached 不支持任何一种。

字符串对于各种用例都是有用的,这就是为什么 memcached 仅对这种数据类型有用。

散列( 命令

哈希有点像键值存储中的键值存储。它们在字符串字段和字符串值之间映射。使用散列的 Field-> value 映射比使用常规字符串的 key-> value 映射在空间效率上略高。

散列可用作名称空间,或者在逻辑上将许多键分组时很有用。使用散列,您可以有效地捕获所有成员,一起使所有成员过期,一起删除所有成员,等等。对于需要将多个键 / 值对进行分组的用例而言,它非常有用。

哈希的一种示例用法是在应用程序之间存储用户配置文件。使用用户 ID 作为密钥存储的 redis 哈希将允许您根据需要存储有关用户的数据,同时将其存储在单个密钥下。使用散列而不是将配置文件序列化为字符串的优点是,您可以让不同的应用程序在用户配置文件中读 / 写不同的字段,而不必担心一个应用程序覆盖其他应用程序所做的更改(如果您将陈旧序列化,则会发生这种情况数据)。

列表( 命令

Redis 列表是字符串的有序集合。它们经过优化,可从列表的顶部或底部(又名:左侧或右侧)插入,读取或删除值。

Redis 的提供许多命令为利用列表,包括命令到压入 / 弹出的项目,推 / 列表,截断列表之间弹出,执行范围查询等

列表使持久的,原子的队列成为可能。这些非常适合作业队列,日志,缓冲区和许多其他用例。

设置( 命令

集是唯一值的无序集合。它们经过优化,可让您快速检查值是否在集合中,快速添加 / 删除值,以及测量与其他集合的重叠。

这些功能非常适合访问控制列表,唯一的访客跟踪器以及许多其他功能。大多数编程语言都有类似的东西(通常称为 Set)。就是这样,只有分布式。

Redis 提供了一些命令来管理集合。存在诸如添加,删除和检查集合之类的显而易见的内容。因此,不太明显的命令(例如弹出 / 读取随机项)以及用于执行与其他集合的并集和交集的命令。

排序集( 命令

排序集也是唯一值的集合。顾名思义,这些是有序的。它们按分数排序,然后按字典顺序排序。

此数据类型经过优化,可按分数快速查找。获得最高,最低或介于两者之间的任何值都非常快。

如果将用户以及他们的高分添加到排序的集合中,则您将拥有一个完美的排行榜。随着新的高分出现,只需将他们的高分再次添加到集合中,它将重新排列排行榜。也非常适合跟踪用户上次访问的时间以及谁在您的应用程序中处于活动状态。

存储具有相同分数的值会使它们按字典顺序(按字母顺序思考)排序。这对于自动完成功能等很有用。

许多排序的 set 命令类似于 set 命令 ,有时带有附加的 score 参数。还包括用于管理分数和按分数查询的命令。

地缘

Redis 的具有几个命令用于存储,检索,以及测量的地理数据。这包括半径查询和测量点之间的距离。

从技术上讲,Redis 中的地理数据存储在排序集中,因此这不是真正的独立数据类型。它更多地是对排序集的扩展。

位图和 HyperLogLog

像 geo 一样,这些也不是完全独立的数据类型。这些命令使您可以将字符串数据视为位图或超级日志。

位图是我在 “ Strings下引用的位级运算符的作用。这种数据类型是 reddit 最近的合作艺术项目r / Place的基本构建块。

HyperLogLog 允许您使用恒定的极少量空间以惊人的精度计算几乎无限的唯一值。仅使用〜16KB,您就可以有效地计算网站唯一身份访问者的数量,即使该数量是数百万。

交易和原子性

Redis 中的命令是原子性的,这意味着您可以确保在向 Redis 写入值后,该值对于连接到 Redis 的所有客户端都是可见的。无需等待该值传播。从技术上讲,memcached 也是原子的,但是 redis 在 memcached 之外添加了所有这些功能,值得注意的是,所有这些其他数据类型和功能也是原子的。

尽管与关系数据库中的事务不太相同,redis 也具有使用 “乐观锁定” 的事务WATCH / MULTI / EXEC )。

流水线

Redis 提供了一个称为 “ 流水线 ” 的功能。如果要执行许多 redis 命令,则可以使用流水线将它们一次发送一次,而不是一次发送到 redis。

通常,当您执行命令以进行 redis 或 memcached 时,每个命令都是一个单独的请求 / 响应周期。使用流水线,redis 可以缓冲多个命令并一次执行所有命令,并在一次回复中对所有命令的所有响应进行响应。

这可以使您在批量导入或涉及许多命令的其他操作上获得更大的吞吐量。

发布 / 订阅

Redis 具有专用于发布 /订阅功能的 命令 ,从而允许 Redis 充当高速消息广播者。这允许单个客户端将消息发布到连接到通道的许多其他客户端。

Redis 可以执行发布 / 订阅以及几乎所有工具。像RabbitMQ这样的专用消息代理可能在某些方面具有优势,但是事实是,同一台服务器还可以为您提供持久的持久队列以及您的发布 / 订阅工作负载可能需要的其他数据结构,Redis 通常被证明是最好,最简单的工具为了工作。

Lua 脚本

您可以想到lua 脚本,例如 redis 自己的 SQL 或存储过程。它的大小不一,但这个类比大都可行。

也许您希望 redis 执行复杂的计算。也许您负担不起事务回滚,需要保证复杂过程的每一步都将自动发生。这些问题以及更多问题可以通过 lua 脚本解决。

整个脚本是原子执行的,因此,如果您可以使逻辑适合 lua 脚本,则通常可以避免混淆乐观的锁定事务。

缩放比例

如上所述,redis 包括对集群的内置支持,并与它自己的称为redis-sentinel的高可用性工具捆绑在一起。

结论

毫不犹豫地,对于任何新项目或尚未使用 memcached 的现有项目,我建议在 memcached 上使用 redis。

以上听起来像我不喜欢 memcached。相反:它是一个功能强大,简单,稳定,成熟和强化的工具。甚至在某些用例中,它比 redis 快一点。我喜欢记忆快取。我只是认为这对未来的发展没有多大意义。

Redis 可以做 memcached 所做的一切,通常更好。 memcached 的任何性能优势都是次要的且特定于工作负载。还有一些工作量的 Redis 会更快,而 Redis 可以做的事情更多,而 Memcached 根本做不到。面对功能上的巨大鸿沟,微小的性能差异似乎微不足道,而且两个工具是如此之快和高效,它们很可能成为基础架构的最后一部分,您将不必担心扩展。

只有一种情况使 memcached 更有意义:将 memcached 用作缓存。如果您已经使用 memcached 进行缓存,请在满足您需要的情况下继续使用它。迁移到 Redis 可能不值得,如果您仅将 Redis 用于缓存,则可能无法提供足够的好处,值得您花时间。如果 memcached 不能满足您的需求,那么您可能应该改用 Redis。无论您需要扩展到内存缓存之外还是需要其他功能,这都是事实。

如果使用 Redis

  1. 您需要有选择地删除 / 过期缓存中的项目。 (你需要这个)

  2. 您需要能够查询特定类型的键。 eq。 'blog1:posts:*','blog2:categories:xyz:posts:*'。哦耶!这个非常重要。使用此选项有选择地使某些类型的缓存项无效。您还可以使用它来使片段缓存,页面缓存,仅给定类型的 AR 对象等无效。

  3. 持久性(您也将需要此持久性,除非您对每次重新启动后都必须预热的缓存没有问题。对于很少更改的对象非常重要)

如果使用 memcached

  1. Memcached 让您头疼!
  2. 嗯... 群集吗?嗯如果要走的那么远,请使用 Varnish 和 Redis 缓存片段和 AR 对象。

根据我的经验,Redis 的稳定性要比 Memcached 好得多

Memcached 是多线程且快速的。

Redis 具有很多功能,并且速度非常快,但是由于它基于事件循环,因此完全限于一个内核。

我们都使用。 Memcached 用于缓存对象,主要是减少数据库上的读取负载。 Redis 用于诸如排序集之类的事情,对于汇总时间序列数据非常有用。

这太长了,无法发布为已经接受的答案的评论,因此我将其作为单独的答案

还需要考虑的一件事是,您是否希望对缓存实例具有严格的内存上限。

由于 redis 是具有大量功能的 nosql 数据库,并且缓存仅是可以使用的一个选项,因此它会根据需要分配内存 - 放入的对象越多,使用的内存就越多。 maxmemory选项不会严格执行内存使用上限。当您使用缓存时,密钥将被逐出并过期。可能是您的密钥的大小不尽相同,因此会发生内部存储器碎片。

默认情况下,redis 使用jemalloc内存分配器,该内存分配器会尽力做到紧凑和快速,但它是通用内存分配器,无法跟上大量分配和对象清除的速度。因此,在某些负载模式下,由于内部碎片,redis 进程显然会泄漏内存。例如,如果您有一台具有 7 Gb RAM 的服务器,并且想将 Redis 用作非持久性 LRU 缓存,那么您可能会发现随着时间的推移, maxmemory设置为 5Gb 的 redis 进程将使用越来越多的内存,最终达到总 RAM 限制直到内存不足的杀手进行干预。

memcached 更适合上述情况,因为它以完全不同的方式管理内存。 memcached 会分配一大块内存(它将需要的所有内容),然后使用自己实现的slab 分配器自行管理该内存。而且,当在考虑对象大小的情况下完成 LRU 逐出时,memcached 会努力将内部碎片保持在较低水平,因为它实际上使用了每块 LRU 算法

话虽如此,memcached 在必须强制使用和 / 或可预测内存使用的环境中仍然具有很强的地位。我们尝试使用最新的稳定 redis(2.8.19)作为工作负载为 10-15k op / s 的非持久性基于 LRU 的 Memcached 替换,它泄漏了很多内存;由于相同的原因,相同的工作负载在一天左右的时间内使 Amazon 的 ElastiCache redis 实例崩溃。

Memcached 擅长于简单的键 / 值存储,擅长做键 => STRING。这使得它非常适合会话存储。

Redis 擅长执行 key => SOME_OBJECT。

这实际上取决于您要放入的内容。我的理解是,就性能而言,它们是相当均匀的。

如果您发现一些客观基准,也很幸运,如果您确实找到一些基准,请按我的方式发送。

如果您不介意粗俗的写作风格,那么从可用性的角度来看,Systoilet 博客上的Redis vs Memcached值得一读,但是在得出任何性能方面的结论之前,请务必先阅读注释中的来回内容。存在一些方法上的问题(单线程繁忙循环测试),自从撰写本文以来,Redis 也进行了一些改进。

毫无疑问,没有任何基准测试链接是完整的,因此也请在Dormondo 的 LiveJournalAntirez Weblog 上查看一些相互矛盾的基准测试。

编辑 - 正如 Antirez 所指出的那样,Systoilet 分析相当不完善。即使超出单线程不足,那些基准测试中的许多性能差异也可以归因于客户端库而不是服务器吞吐量。实际上,Antirez Weblog 上的基准确实提供了更多的苹果对苹果(具有相同口)的比较。

我有机会在我使用过的缓存代理中同时使用 memcached 和 redis,让我分享给我我使用过的内容和背后原因的确切位置。

Redis>

1)用于为群集上的缓存内容建立索引。我在 Redis 群集上分布着超过十亿个密钥,Redis 响应时间相当短且稳定。

2)基本上,它是一个键 / 值存储库,因此在您的应用程序中任何有相似之处的地方,都可以使用 redis 进行很多工作。

3)Redis 持久性,故障转移和备份(AOF)将使您的工作更加轻松。

内存缓存 >

1)是,可以用作缓存的优化内存。我用它来存储缓存内容,访问频率非常高(每秒 50 次),大小小于 1 MB。

2)当我的单个内容大小 > 1MB 时,我也仅在 16 GB 内存中分配了 2GB 的内存缓存。

3)随着内容的增长接近极限,我偶尔会在统计数据中观察到更高的响应时间(redis 则不是)。

如果您需要总体体验,Redis 易于配置,非常绿色,具有稳定可靠的功能,非常灵活。

此外,此链接提供了一个基准测试结果,以下是来自同一方面的一些亮点,

在此处输入图片说明

在此处输入图片说明

希望这可以帮助!!

另一个好处是,可以非常清楚地了解内存缓存在缓存情况下的表现方式,而 redis 通常用作持久性数据存储,尽管它可以配置为就像内存缓存一样,也就是在达到最大值时退出最近最少使用的项目容量。

我研究过的一些应用程序都使用了这两种方法,只是为了弄清楚我们打算如何处理数据 - 内存缓存中的内容,我们编写代码来处理数据不存在的情况 - Redis 中的内容,我们依靠它在那里。

除此之外,对于大多数用例而言,Redis 通常被认为是优越的,因为它们具有更多功能,因此更加灵活。

测试。运行一些简单的基准测试。很长一段时间以来,我一直认为自己是一头古老的犀牛,因为我主要使用内存缓存,并认为 Redis 是新孩子。

在我目前的公司中,Redis 被用作主缓存。当我挖到一些性能统计和简单的开始测试,Redis 的是,在性能方面,相当或微创于 MySQL 的。

内存缓存虽然简单,但却使 Redis 完全倒水 。它的伸缩性更好:

  • 更大的值(需要改变板坯尺寸,但可行)
  • 对于多个并发请求

此外,我认为内存缓存逐出策略得到了更好的实施,从而导致整体平均响应时间更加稳定,同时处理的数据量超过了缓存可以处理的范围。

一些基准测试表明,在我们的案例中,Redis 的表现非常差。我认为这与许多变量有关:

  • 您在其上运行 Redis 的硬件类型
  • 您存储的数据类型
  • 获取和设置的数量
  • 您的应用程序的并发程度
  • 您是否需要数据结构存储

就个人而言,我不同意 Redis 作者对并发和多线程的看法。

如果我们说 redis 是(cache + 数据结构)的组合,而 memcached 只是一个缓存,那没有错。