我们正在使用带有Redis服务器的 Ruby Web 应用程序进行缓存。是否有必要改为测试Memcached?
什么会给我们带来更好的表现?Redis 和 Memcached 之间有什么优缺点?
需要考虑的要点:
- 读/写速度。
- 内存使用情况。
- 磁盘 I/O 转储。
- 缩放。
2017 年 6 月 3 日更新
Redis 比 memcached 更强大、更流行、支持更好。Memcached 只能做 Redis 能做的事情的一小部分。Redis 更好,即使它们的功能重叠。
对于任何新事物,请使用 Redis。
这两种工具都是强大、快速的内存数据存储,可用作缓存。两者都可以通过缓存数据库结果、HTML 片段或其他任何生成成本可能很高的东西来帮助加速您的应用程序。
当用于同一事物时,以下是它们使用原始问题的“要考虑的要点”进行比较的方式:
Memcached 是一个简单的易失性缓存服务器。它允许您存储键/值对,其中值被限制为最大 1MB 的字符串。
它擅长这一点,但仅此而已。您可以通过它们的键以极高的速度访问这些值,通常会使可用网络甚至内存带宽饱和。
当您重新启动 memcached 时,您的数据就消失了。这对于缓存来说很好。你不应该在那里存储任何重要的东西。
如果您需要高性能或高可用性,可以使用第三方工具、产品和服务。
Redis 可以完成与 memcached 相同的工作,并且可以做得更好。
Redis 也可以充当缓存。它也可以存储键/值对。在 redis 中,它们甚至可以达到 512MB。
您可以关闭持久性,它也会很高兴在重新启动时丢失您的数据。如果您希望您的缓存在重新启动后仍然存在,那么您也可以这样做。事实上,这是默认设置。
它也非常快,通常受到网络或内存带宽的限制。
如果一个 redis/memcached 实例的性能不足以满足您的工作负载,那么 redis 是明确的选择。Redis 包括集群支持,并带有高可用性工具(redis-sentinel)“在盒子里”。在过去的几年里,redis 也已成为 3rd 方工具的明显领导者。Redis Labs、Amazon 等公司提供许多有用的 redis 工具和服务。redis 周围的生态系统要大得多。大规模部署的数量现在可能比 memcached 多。
Redis 不仅仅是一个缓存。它是一个内存数据结构服务器。您将在下面快速了解 Redis 可以做的事情,而不仅仅是像 memcached 这样的简单键/值缓存。redis 的大部分功能都是 memcached 无法做到的。
Redis 比 memcached 有更好的文档记录。虽然这可能是主观的,但它似乎越来越真实。
redis.io是一个很棒的易于导航的资源。它让您可以在浏览器中尝试 redis,甚至可以为您提供文档中每个命令的实时交互式示例。
现在 redis 的 stackoverflow 结果是 memcached 的 2 倍。2 倍的 Google 结果。更多语言的更易于访问的示例。更积极的发展。更积极的客户开发。这些测量单独可能意义不大,但结合起来,它们描绘了一幅清晰的画面,即对 redis 的支持和文档更加强大,并且更加最新。
默认情况下,redis 使用一种称为快照的机制将数据持久化到磁盘。如果您有足够的 RAM 可用,它能够将所有数据写入磁盘而几乎不会降低性能。它几乎是免费的!
在快照模式下,突然崩溃可能会导致少量数据丢失。如果您绝对需要确保不会丢失任何数据,请不要担心,redis 也支持 AOF(仅附加文件)模式。在这种持久性模式下,数据可以在写入时同步到磁盘。这可以将最大写入吞吐量降低到磁盘可以写入的速度,但仍然应该非常快。
如果需要,有许多配置选项可以微调持久性,但默认值非常合理。这些选项可以轻松地将 redis 设置为存储数据的安全、冗余的地方。它是一个真正的数据库。
Memcached 仅限于字符串,但 Redis 是一种数据结构服务器,可以提供许多不同的数据类型。它还提供了充分利用这些数据类型所需的命令。
最大为 512MB 的简单文本或二进制值。这是 redis 和 memcached 共享的唯一数据类型,尽管 memcached 字符串限制为 1MB。
Redis 通过提供用于按位运算、位级操作、浮点递增/递减支持、范围查询和多键操作的命令,为您提供了更多利用此数据类型的工具。Memcached 不支持这些。
字符串对各种用例都很有用,这就是 memcached 单独用于这种数据类型的原因。
哈希有点像键值存储中的键值存储。它们在字符串字段和字符串值之间映射。使用散列的字段-> 值映射比使用常规字符串的键-> 值映射更节省空间。
哈希可用作命名空间,或者当您想要对许多键进行逻辑分组时。使用散列,您可以有效地获取所有成员、将所有成员一起过期、一起删除所有成员等。非常适合您有多个需要分组的键/值对的任何用例。
哈希的一个示例使用是用于在应用程序之间存储用户配置文件。使用用户 ID 作为键存储的 redis 哈希将允许您根据需要存储有关用户的尽可能多的数据位,同时将它们存储在单个键下。使用哈希而不是将配置文件序列化为字符串的优点是,您可以让不同的应用程序读取/写入用户配置文件中的不同字段,而不必担心一个应用程序会覆盖其他应用程序所做的更改(如果您序列化陈旧,则可能会发生这种情况数据)。
Redis 列表是有序的字符串集合。它们针对从列表的顶部或底部(又名:左侧或右侧)插入、读取或删除值进行了优化。
Redis 提供了许多用于利用列表的命令,包括推送/弹出项目、列表之间的推送/弹出、截断列表、执行范围查询等命令。
列表是非常持久的原子队列。它们非常适用于作业队列、日志、缓冲区和许多其他用例。
集合是唯一值的无序集合。它们经过优化,可让您快速检查值是否在集合中,快速添加/删除值,并测量与其他集合的重叠。
这些非常适合访问控制列表、唯一访客跟踪器和许多其他事物。大多数编程语言都有类似的东西(通常称为 Set)。就是这样,只是分布式的。
Redis 提供了几个命令来管理集合。存在诸如添加、删除和检查集合之类的明显操作。诸如弹出/读取随机项目以及与其他集合执行联合和交集的命令等不太明显的命令也是如此。
排序集也是唯一值的集合。顾名思义,这些是有序的。它们按分数排序,然后按字典顺序排列。
此数据类型针对按分数快速查找进行了优化。获得最高、最低或介于两者之间的任何值范围都非常快。
如果您将用户连同他们的高分一起添加到排序集中,您就拥有了一个完美的排行榜。当新的高分出现时,只需将他们的高分再次添加到集合中,它就会重新排列您的排行榜。也非常适合跟踪用户上次访问的时间以及谁在您的应用程序中处于活动状态。
存储具有相同分数的值会使它们按字典顺序排列(按字母顺序排列)。这对于诸如自动完成功能之类的东西很有用。
许多排序集命令类似于集命令,有时带有额外的分数参数。还包括用于管理分数和按分数查询的命令。
Redis 有几个用于存储、检索和测量地理数据的命令。这包括半径查询和测量点之间的距离。
从技术上讲,redis 中的地理数据存储在排序集中,因此这不是一个真正独立的数据类型。它更像是排序集之上的扩展。
像地理一样,这些不是完全独立的数据类型。这些命令允许您将字符串数据视为位图或超级日志。
位图是我在下面引用的位级运算符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这样的专用消息代理可能在某些领域具有优势,但事实上,同一台服务器还可以为您提供持久的持久队列和您的 pub/sub 工作负载可能需要的其他数据结构,Redis 通常会被证明是最好和最简单的工具为了工作。
您可以将lua 脚本想象成redis 自己的 SQL 或存储过程。它既多又少,但这个类比大多是有效的。
也许你有想要 redis 执行的复杂计算。也许您不能让您的事务回滚,并且需要保证复杂过程的每一步都将自动发生。这些问题以及更多问题都可以通过 lua 脚本来解决。
整个脚本是原子执行的,因此如果您可以将逻辑放入 lua 脚本中,您通常可以避免与乐观锁定事务混淆。
如上所述,redis 包含对集群的内置支持,并与它自己的高可用性工具捆绑在一起,称为redis-sentinel
.
对于任何新项目或尚未使用 memcached 的现有项目,我会毫不犹豫地推荐 redis 而不是 memcached。
以上可能听起来我不喜欢memcached。相反:它是一个强大、简单、稳定、成熟和硬化的工具。甚至在一些用例中它比 redis 快一点。我喜欢内存缓存。我只是认为这对未来的发展没有多大意义。
Redis 完成了 memcached 所做的一切,而且通常做得更好。memcached 的任何性能优势都是次要的,并且是特定于工作负载的。还有一些工作负载 redis 会更快,还有更多的工作负载 redis 可以做而 memcached 根本做不到。面对巨大的功能鸿沟,微小的性能差异似乎微不足道,而且这两种工具都非常快速和高效,它们很可能是您永远不必担心扩展的基础架构的最后一块。
只有一种情况下 memcached 更有意义:memcached 已经用作缓存。如果您已经使用 memcached 进行缓存,那么如果它满足您的需求,请继续使用它。迁移到 redis 可能不值得付出努力,如果您仅将 redis 用于缓存,它可能无法提供足够的好处,不值得您花时间。如果 memcached 不能满足您的需求,那么您可能应该转向 redis。无论您需要超越 memcached 还是需要其他功能,这都是正确的。
使用 Redis 如果
您需要有选择地删除/过期缓存中的项目。(你需要这个)
您需要能够查询特定类型的键。等式。'blog1:posts:*'、'blog2:categories:xyz:posts:*'。哦耶!这个非常重要。使用它可以选择性地使某些类型的缓存项无效。您还可以使用它来使片段缓存、页面缓存、仅给定类型的 AR 对象等无效。
持久性(你也需要这个,除非你对每次重新启动后必须预热缓存没问题。对于很少更改的对象非常重要)
使用 memcached 如果
根据我的经验,我使用 Redis 的稳定性比 Memcached 好得多
Memcached 是多线程且快速的。
Redis 有很多功能并且速度非常快,但由于它基于事件循环,因此完全限于一个核心。
我们两者都用。Memcached 用于缓存对象,主要是减少数据库的读取负载。Redis 用于诸如排序集之类的东西,它们可以方便地汇总时间序列数据。
这太长了,不能作为对已经接受的答案的评论发布,所以我把它作为一个单独的答案
还需要考虑的一件事是您是否希望缓存实例具有硬的内存上限。
由于 redis 是一个具有大量功能的 nosql 数据库,并且缓存只是它可以使用的一个选项,它会根据需要分配内存——你放入的对象越多,它使用的内存就越多。该maxmemory
选项不严格强制使用内存上限。当您使用缓存时,密钥会被逐出并过期;很可能您的密钥大小不一样,因此会发生内部内存碎片。
默认情况下,redis 使用jemalloc内存分配器,它尽最大努力实现内存紧凑和快速,但它是一个通用的内存分配器,它无法跟上大量的分配和高速发生的对象清除。正因为如此,在某些加载模式下,redis 进程显然会由于内部碎片而泄漏内存。例如,如果你有一个 7 Gb RAM 的服务器并且你想使用 redis 作为非持久 LRU 缓存,你可能会发现maxmemory
随着时间的推移设置为 5Gb 的 redis 进程会使用越来越多的内存,最终达到总 RAM 限制,直到内存不足的杀手干扰。
memcached 更适合上述场景,因为它以完全不同的方式管理其内存。memcached 分配一大块内存——它需要的一切——然后使用自己实现的slab分配器自行管理这块内存。此外,memcached 努力保持低内部碎片,因为它实际上使用 per-slab LRU 算法,当 LRU 驱逐是在考虑对象大小的情况下完成的。
话虽如此,memcached 在必须强制执行和/或可预测内存使用的环境中仍然具有强大的地位。我们尝试在 10-15k op/s 的工作负载中使用最新的稳定版 redis (2.8.19) 作为基于 LRU 的非持久性 memcached 替代品,但它泄漏了很多内存;由于相同的原因,相同的工作负载在一天左右的时间内使 Amazon 的 ElastiCache redis 实例崩溃。
Memcached 擅长做简单的 key/value 存储,擅长做 key => STRING。这使得它非常适合会话存储。
Redis 擅长做 key => SOME_OBJECT。
这真的取决于你要在那里放什么。我的理解是,就性能而言,它们相当均衡。
也祝你好运找到任何客观的基准,如果你确实找到了一些,请将它们发送给我。
如果您不介意粗俗的写作风格,从可用性的角度来看,Systoilet 博客上的Redis 与 Memcached值得一读,但在对性能做出任何结论之前,请务必阅读评论中的来回信息;存在一些方法问题(单线程忙循环测试),并且 Redis 也从撰写本文开始进行了一些改进。
没有一个基准链接是完整的而不会使事情有点混乱,所以还可以在Dormondo 的 LiveJournal和Antirez Weblog上查看一些相互冲突的基准。
编辑——正如 Antirez 指出的那样,Systoilet 分析的构思很糟糕。即使超出了单线程的不足,这些基准测试中的大部分性能差异也可以归因于客户端库而不是服务器吞吐量。Antirez 博客上的基准确实提供了更多的苹果对苹果(同一张嘴)的比较。
我有机会在我工作过的缓存代理中同时使用 memcached 和 redis,让我分享一下我到底在哪里使用了什么以及背后的原因......
雷迪斯 >
1) 用于在集群上索引缓存内容。我有超过十亿个键分布在 redis 集群中,redis 响应时间非常短且稳定。
2)基本上,它是一个键/值存储,所以无论在你的应用程序中,无论你有什么类似的东西,都可以使用 redis 来麻烦很多。
3) Redis 持久性、故障转移和备份 (AOF) 将使您的工作更轻松。
内存缓存 >
1)是的,可以用作缓存的优化内存。我用它来存储缓存内容被非常频繁地访问(每秒 50 次),大小小于 1 MB。
2) 当我的单个内容大小为 >1MB 时,我也只为 memcached 分配了 16 GB 中的 2GB。
3)随着内容的增长接近极限,有时我会在统计数据中观察到更高的响应时间(redis 不是这种情况)。
如果您要求整体体验,Redis 非常绿色,因为它易于配置、非常灵活且具有稳定的强大功能。
此外,此链接上有一个基准测试结果,以下是相同的几个亮点,
希望这可以帮助!!
测试。运行一些简单的基准测试。很长一段时间以来,我都认为自己是一头老派犀牛,因为我主要使用 memcached,并认为 Redis 是新来的。
在我目前的公司中,Redis 被用作主缓存。当我深入研究一些性能统计数据并开始测试时,Redis 在性能方面与MySQL相当或稍慢。
Memcached,虽然很简单,却彻底把 Redis彻底淘汰了。它的扩展性要好得多:
此外,在我看来,memcached 驱逐策略实施得更好,从而在处理比缓存能够处理的更多数据的同时,总体上更稳定的平均响应时间。
一些基准测试显示,在我们的案例中,Redis 的性能非常差。我认为这与许多变量有关:
就个人而言,我不同意 Redis 作者对并发和多线程的看法。
另一个好处是它可以非常清楚 memcache 在缓存场景中的行为方式,而 redis 通常用作持久性数据存储,尽管它可以配置为就像 memcached 也就是在达到最大值时驱逐最近最少使用的项目容量。
我工作过的一些应用程序使用这两种方法只是为了明确我们希望数据如何表现——内存缓存中的东西,我们编写代码来处理它不存在的情况——redis中的东西,我们依赖它存在.
除此之外,Redis 通常被认为对于大多数功能更丰富、因此更灵活的用例来说更胜一筹。
如果我们说redis是(缓存+数据结构)的组合,而memcached只是一个缓存,那就没有错。
针对 redis-2.2.2 和 memcached 设置和获取 100k 唯一键和值的非常简单的测试。两者都在 linux VM(CentOS)上运行,我的客户端代码(粘贴在下面)在 Windows 桌面上运行。
雷迪斯
存储 100000 个值所需的时间为 = 18954 毫秒
加载 100000 个值所需的时间为 = 18328 毫秒
内存缓存
存储 100000 个值所需的时间为 = 797ms
检索 100000 个值所需的时间为 = 38984 毫秒
Jedis jed = new Jedis("localhost", 6379);
int count = 100000;
long startTime = System.currentTimeMillis();
for (int i=0; i<count; i++) {
jed.set("u112-"+i, "v51"+i);
}
long endTime = System.currentTimeMillis();
System.out.println("Time taken to store "+ count + " values is ="+(endTime-startTime)+"ms");
startTime = System.currentTimeMillis();
for (int i=0; i<count; i++) {
client.get("u112-"+i);
}
endTime = System.currentTimeMillis();
System.out.println("Time taken to retrieve "+ count + " values is ="+(endTime-startTime)+"ms");
此处未指出的一个主要区别是 Memcache 始终具有内存上限,而 Redis 默认情况下没有(但可以配置为)。如果您总是想在一定时间内存储一个键/值(并且永远不会因为内存不足而将其驱逐),那么您希望使用 Redis。当然,你也冒着内存不足的风险......
如果您对性能感兴趣,Memcached 会更快,即使因为 Redis 涉及网络(TCP 调用)。在内部,Memcache 也更快。
Redis 具有其他答案中提到的更多功能。
我们认为 Redis 是我们工作中项目的负载起飞。我们认为通过在nginx
调用中使用模块HttpRedis2Module
或类似的东西,我们会获得惊人的速度,但是当使用 AB-test 进行测试时,我们被证明是错误的。
也许模块不好或者我们的布局,但这是一个非常简单的任务,使用 php 获取数据然后将其填充到 MongoDB 中甚至更快。我们使用 APC 作为缓存系统以及 php 和 MongoDB。nginx
它比Redis 模块快得多。
我的建议是自己测试它,这样做会向您显示您的环境的结果。我们认为在我们的项目中没有必要使用 Redis,因为它没有任何意义。
剩下的最大原因是专业化。
Redis 可以做很多不同的事情,其中一个副作用是开发人员可能会开始在同一个实例上使用很多不同的功能集。如果您将 Redis 的 LRU 功能用于非 LRU 的硬数据存储旁边的缓存,则完全有可能耗尽内存。
如果您要设置一个专用的 Redis 实例,仅用作 LRU 实例以避免这种特定情况,那么实际上没有任何令人信服的理由使用 Redis 而不是 Memcached。
如果你需要一个可靠的“永不宕机”的 LRU 缓存......Memcached 将符合要求,因为它不可能在设计上耗尽内存,并且专门的功能阻止开发人员尝试使其成为可能危及它的东西。简单的关注点分离。
Redis 更好。
的优点Redis
是,
LUA
脚本)支持而Memcache
内存中的键值缓存类型系统。
这是亚马逊提供的非常棒的文章/差异
与 memcached 相比,Redis 是明显的赢家。
Memcached 只有一个优点, 它是多线程的,速度很快。Redis 有很多很棒的功能,速度非常快,但仅限于一个核心。
关于 Redis 的要点,Memcached 不支持这些要点