Memcached和Redis有什么区别?

1483
我们正在使用一个带有Redis服务器缓存的Ruby Web应用程序。是否有必要测试Memcached呢?
哪个会给我们更好的性能? Redis和Memcached之间有什么优缺点?
需要考虑以下几点:
  • 读写速度。
  • 内存使用。
  • 磁盘I/O转储。
  • 扩展。

38
除下面的评论外,还有一个分析:Google 趋势:redis vs. memcached - MarkHu
4
一个不值得回答的评论:如果你正在寻找这两个系统的云服务(例如Heroku附加组件),由于某种原因,Memcached服务有时每MB会便宜很多。 - B Robster
3
为了可扩展性:Imgur和Twitter都使用 - the_red_baron
17个回答

2138

摘要(TL;DR)

更新于2017年6月3日

Redis比memcached更加强大、流行和得到更好的支持。Memcached只能做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明显胜出,因为它默认执行此操作并具有可配置的持久性。Memcached没有借助第三方工具进行转储的机制。
  • 扩展性:在需要单个实例作为缓存之前,两者都可以提供大量余地。Redis包括帮助您超越这一点的工具,而memcached则没有。

memcached

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

它擅长于这一点,但这就是它所能做的全部。您可以通过其键极快地访问这些值,通常会饱和可用的网络甚至内存带宽。

当您重新启动memcached时,您的数据将消失。这对于缓存来说很好。您不应该在那里存储任何重要内容。

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

redis

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

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

您可以关闭持久性,在重新启动时它会愉快地丢失您的数据。如果您希望缓存在重新启动后仍然存在,它也可以让您这样做。事实上,这是默认设置。

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

如果一个redis/memcached实例的性能不足以满足您的工作量,那么redis是明显的选择。Redis包括集群支持并配备了高可用性工具(redis-sentinel),这些都在“盒子”中。近年来,redis也成为第三方工具的明显领导者。像Redis Labs,Amazon和其他公司提供了许多有用的redis工具和服务。围绕redis的生态系统更大。现在,大规模部署的数量可能比memcached更多。

Redis超集

Redis不仅是缓存。它还是一个内存数据结构服务器。以下是Redis可以执行的一些快速概述,超出了像memcached这样的简单键/值缓存。 Redis的大多数功能是memcached无法完成的。

文档

Redis的文档比memcached更好。虽然这可能是主观的,但它似乎越来越真实。

redis.io 是一个非常好用、易于导航的资源。它可以让您在浏览器中 尝试redis,并且在文档中每个命令都提供了实时交互式示例。

现在,与memcached相比,redis在stackoverflow上的结果是2倍,谷歌搜索结果也是2倍。同时提供更多语言的示例,开发活跃度更高,客户端开发更加活跃。这些指标单独来看可能意义不大,但综合起来,它们清晰地表明redis的支持和文档更加强大和更新。

持久化

默认情况下,redis使用一种称为快照机制的方法将您的数据持久化到磁盘上。如果您有足够的RAM可用,它几乎可以在没有性能降级的情况下将所有数据写入磁盘。这几乎是免费的!

在快照模式下,突然崩溃可能导致少量数据丢失。如果您绝对需要确保没有数据丢失,不用担心,redis也有AOF(仅追加文件)模式来支持您。在这种持久性模式下,数据可以在写入时同步到磁盘。这可能会将最大写入吞吐量降低到磁盘写入速度的速度,但应该仍然非常快。
如果需要,有许多配置选项可微调持久性,但默认设置非常合理。这些选项使得将redis设置为安全、冗余的数据存储位置变得容易。它是一个真正的数据库。
许多数据类型
Memcached仅限于字符串,但Redis是一个数据结构服务器,可以提供许多不同的数据类型。它还提供了您需要利用这些数据类型的命令。
字符串(commands
简单的文本或二进制值,大小可达512MB。这是redis和memcached共享的唯一数据类型,尽管memcached字符串仅限于1MB。

Redis提供了更多的工具来利用这种数据类型,通过提供位运算、位级操作、浮点数增量/减量支持、范围查询和多键操作命令。Memcached不支持这些功能。

字符串在各种用例中都很有用,这就是为什么仅使用这种数据类型时,Memcached也相当有用。

哈希(命令)

哈希有点像一个键值存储中的键值存储。它们将字符串字段与字符串值映射起来。使用哈希的字段->值映射比使用常规字符串的键->值映射稍微更节省空间。

哈希作为命名空间很有用,或者当您想要逻辑上分组许多键时。使用哈希,您可以高效地获取所有成员、一起过期所有成员、一起删除所有成员等。非常适合任何需要分组多个键/值对的用例。

一个哈希表的实例应用是在不同应用之间存储用户资料。使用以用户ID为键值的Redis哈希表可以让您存储任意数量的关于用户的数据,同时将它们存储在单个键下。使用哈希表的好处是,相比将用户资料序列化成字符串,您可以让不同的应用程序读取/写入用户资料中的不同字段,而无需担心其中一个应用程序会覆盖其他应用程序所做的更改(如果您序列化了过期数据,则可能会发生这种情况)。

列表 (命令)

Redis列表是有序的字符串集合。它们被优化为从列表的顶部或底部(也称为左侧或右侧)插入、读取或删除值。

Redis提供了许多命令来利用列表,包括推送/弹出项目、在列表之间推送/弹出、截断列表、执行范围查询等。

列表非常适合用作持久性、原子性队列。这对于作业队列、日志、缓冲区和许多其他用例非常有效。

集合 (命令)

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

这些非常适用于访问控制列表、独特的访问者跟踪器等许多其他事情。大多数编程语言都有类似的东西(通常称为Set)。这就像那样,只是分布式的。

Redis提供了几个命令来管理集合。显而易见的是添加、删除和检查集合。还有一些不太明显的命令,例如弹出/读取随机项以及与其他集合执行联合和交集的命令。

排序集合 (命令)

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

这种数据类型被优化为通过分数快速查找。获取最高、最低或任何介于其间的一系列值非常快速。

如果您将用户与其高分数一起添加到排序集中,您就拥有了一个完美的排行榜。随着新的高分数的出现,只需再次将它们与其高分数添加到集合中,它就会重新排序您的排行榜。还非常适用于跟踪用户上次访问的时间以及谁在您的应用程序中处于活动状态。
使用相同分数存储值会使它们按字典顺序排序(类似于按字母顺序)。这对于自动完成功能等事情非常有用。
许多排序集 commands 与集合命令类似,有时还带有额外的分数参数。还包括管理分数和按分数查询的命令。

地理位置

Redis有几个commands用于存储、检索和测量地理数据。这包括半径查询和测量点之间的距离。
从技术上讲,redis中的地理数据存储在排序集中,因此这不是一个真正的单独数据类型。它更像是在排序集之上的扩展。

位图和HyperLogLog

像 geo 一样,这些并不是完全独立的数据类型。这些命令允许您将字符串数据视为位图或超级对数。

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

HyperLogLog 允许您使用极小的常量空间计数几乎无限的唯一值,并具有惊人的准确性。只使用 ~16KB,即使访问者数量达到百万级别,您也可以高效地计算出网站的唯一访问者数量。

事务和原子性

Redis 中的命令是原子的,这意味着您可以确信,只要您将一个值写入 Redis,该值就对连接到 Redis 的所有客户端可见。没有等待该值传播的时间。从技术上讲,memcached 也是原子的,但是随着 Redis 添加了所有这些功能,超越了 memcached,值得注意的是,所有这些附加的数据类型和功能也是原子的,这相当令人印象深刻。

虽然与关系型数据库中的事务不完全相同,但redis也有transactions,使用“乐观锁定”(WATCH/MULTI/EXEC)。

管道技术

Redis提供了一个名为“pipelining”的功能。如果您想执行许多redis命令,可以使用管道技术将它们一次性发送到redis,而不是逐个发送。

通常情况下,当您向redis或memcached执行命令时,每个命令都是单独的请求/响应周期。使用管道技术,redis可以缓冲多个命令并同时执行它们,以单个回复响应所有命令的所有响应。

这可以让您在涉及大量命令的批量导入或其他操作中实现更高的吞吐量。

发布/订阅

Redis有commands专门用于pub/sub功能,使redis成为高速消息广播器。这允许单个客户端向连接到频道的许多其他客户端发布消息。
Redis在pub/sub方面的表现几乎与任何工具一样好。像RabbitMQ这样的专用消息代理可能在某些领域具有优势,但是同一服务器还可以为您提供持久的耐用队列和其他数据结构,这些数据结构很可能需要pub/sub工作负载,因此Redis通常被证明是最好的和最简单的工具。

Lua脚本

您可以将lua脚本视为redis自己的SQL或存储过程。它既是更多又是更少,但类比大多数情况下都适用。
也许您有复杂的计算要求redis执行。也许您无法承担事务回滚并且需要保证复杂流程的每个步骤都会以原子方式发生。这些问题以及许多其他问题都可以通过lua脚本解决。
整个脚本是原子执行的,因此如果您可以将逻辑放入lua脚本中,通常可以避免与乐观锁定事务交互的麻烦。
缩放
如上所述,Redis包括内置支持群集,并捆绑了自己的高可用性工具redis-sentinel。
结论
毫不犹豫地,我会推荐Redis而不是memcached用于任何新项目或尚未使用memcached的现有项目。
以上可能听起来像我不喜欢memcached。相反:它是一种强大、简单、稳定、成熟和经过硬化的工具。甚至有些用例它比redis更快。我爱memcached。我只是认为对于未来的发展来说它没有太多意义。
Redis做的所有事情都可以由memcached完成,而且通常做得更好。memcached的任何性能优势都是微小的且特定于工作负载的。还有一些工作负载,Redis将更快,Redis可以做很多memcached根本无法做到的工作负载。在功能巨大的鸿沟和两个工具如此快速和高效以至于它们可能是您永远不必担心缩放的基础设施的最后一块拼图的情况下,微小的性能差异似乎不重要。
只有一种情况使用memcached才更有意义:当memcached已经被用作缓存时。如果您已经在使用memcached进行缓存,请继续使用它,如果它能满足您的需求。迁移到redis可能不值得努力,如果您只是为了缓存而使用redis,则可能没有足够的好处来值得您投入时间。如果memcached不能满足您的需求,那么您应该考虑迁移到redis。这是无论您需要超越memcached扩展还是需要额外功能都是正确的决定。

11
Memcached如何通过服务器本身提供聚类功能?我通常使用分布式哈希算法或取模算法将库分发到Memcached服务器池中。Redis也是如此。我主要使用Python,似乎有很多模块不依赖于Memcached库来处理连接池。 - whardier
2
"具有乐观锁定的事务(WATCH/MULTI/EXEC)" - Redis没有正确的事务处理。即,如果[multi,cmd1,cmd2,cmd3(异常),exec],则将执行cmd1和cmd2。 - ZedZip
10
@Oleg,那其实不是真的。如果您使用multi-exec,则命令会被缓冲(即:未执行),直到发生exec为止,因此如果在exec之前出现异常,则实际上不会执行任何命令。如果调用了exec,则所有缓冲的命令都会以原子方式执行,除非在multi第一次调用后已更改监视变量。后一种机制是乐观锁定的一部分。 - Carl Zulauf
3
您说得对。更新回答以反映memcached集群“支持”是通过额外的工具启用的。应该更好地进行研究。 - Carl Zulauf
3
使用Couchbase Server进行聚类如何?(与Memcached兼容) - Ken Liu
显示剩余14条评论

142

如果您需要有选择地删除/过期缓存中的项目,请使用Redis。(您需要这个)

  1. 如果您需要查询特定类型的键,例如“blog1:posts:*”,“blog2:categories:xyz:posts:*”等等。这非常重要。使用此功能可以有选择性地使某些类型的缓存项失效,也可以用于无效化片段缓存、页面缓存、给定类型的AR对象等。

  2. 持久化(除非您不介意每次重新启动后都要重新填充缓存,否则您也需要此功能。对于很少更改的对象非常重要)

如果:

  1. Memcached让您头疼!
  2. 嗯...群集吗?算了吧。如果您要走到那一步,请使用Varnish和Redis来缓存片段和AR对象。

根据我的经验,Redis比Memcached更加稳定。


7
Redis文档说明使用模式需要进行表扫描。例如,使用“blog1:posts:*”可能需要进行O(N)的表扫描。当然,在合理大小的数据集上仍然非常快,因为Redis很快。这对于测试或管理是可以的。 - wisty
186
“Headached” 是一个玩笑,对吧? :-) 我用谷歌搜索了“memcached headached”,但没有找到任何有意义的结果。(我是 Memcached 和 Redis 的新手) - KajMagnus
12
由于和 @pellucide 一样的原因,被投票 否决 。Redis可能比Memcached更好,但是Memcached很容易使用。我从未遇到过问题,而且它很容易配置。 - Diego Jancic
Redis是最容易使用的技术之一。即使没有先前的Redis知识,我只用了20分钟就在云中使用包管理器将其安装在Ubuntu上,并开始进行简单的查询。4个小时后,我可以使用Lua脚本POC更复杂的场景,并选择正确的(NIO)Java库来提高性能。我无法想象比Redis更友好和简单的东西了。 - Andriy Kharchuk

109

Memcached是多线程且快速的。

Redis具有许多功能且非常快,但完全限制在一个核心上,因为它基于事件循环。

我们同时使用两者。Memcached 用于缓存对象,主要减少数据库的读取负载。Redis 用于像排序集这样的东西,非常适用于汇总时间序列数据。


2
那些在memcached上投入较多并且在“用户配置文件”类似的非关系型数据上存在数据库瓶颈的高流量网站应该与通常的Mongo和Redis同时评估couchbase - user246672
2
@siliconrockstar - 我很确定Redis 3仍然是单核心的;至少AWS Redis(使用3.2.6或3.2.10)在查看例如EngineCpuUtilization Metrics时警告要考虑到这一点。 - dwanderson
1
看起来你是对的,我想当我发表那个评论时,我基于不完整的信息。已删除评论。 - siliconrockstar
但是你仍然可以启动 $core_count 个 Redis 实例。 - Imaskar
2
Redis非常注重效率-因此您需要问自己为什么一群聪明的开发人员选择将其保持单线程?从Redis文档中可以看到:“通常情况下,Redis不会成为CPU瓶颈,因为Redis通常是内存或网络受限”。如果您要使用一个CPU受限的服务器,则可能有许多用户,并且应该拥有多个冗余服务器。如果您想在单个服务器上最大化多个CPU,请使用分区。阅读:https://redis.io/topics/faq#redis-is-single-threaded-how-can-i-exploit-multiple-cpu--cores - robocat

92

这段内容太长了,不能作为已接受的答案的评论发布,因此我将其作为单独的答案发布

还有一件事需要考虑,那就是您是否预计在缓存实例上设置硬上限内存。

由于redis是一个nosql数据库,具有大量功能并且缓存只是其中之一,因此它会根据需要分配内存-您放置的对象越多,它使用的内存就越多。 maxmemory选项不严格强制执行上限内存限制。在使用缓存时,键被逐出和过期;可能您的键大小不同,因此会发生内部内存碎片。

默认情况下,redis使用jemalloc 内存分配器,它尽最大努力既紧凑又快,但它是一种通用的内存分配器,无法跟上高速发生的大量分配和对象清除。由于这个原因,在某些负载模式下,redis进程可能会因内部碎片而泄漏内存。例如,如果您的服务器有7 Gb RAM,并且您希望将redis用作非持久LRU缓存,则可能会发现将maxmemory设置为5 Gb的redis进程会随着时间的推移而使用越来越多的内存,最终达到总RAM限制,直到内存杀手干预。

memcached更适合上述场景,因为它以完全不同的方式管理内存。 memcached分配一个大内存块-它将永远需要的所有东西-然后自己管理此内存,使用其自己实现的slab分配器。此外,memcached努力保持内部碎片低,因为它实际上使用每个slab的LRU算法,当考虑对象大小时进行LRU逐出。

话虽如此,memcached仍然在需要强制执行和/或可预测内存使用的环境中占据着强势地位。我们尝试将最新稳定版本的redis(2.8.19)作为一种即插即用、非持久性、基于LRU的memcached替代方案,在每秒10-15k次操作的工作负载中进行测试,结果发现它大量泄漏内存;同样的工作负载会因为同样的原因,在一天左右时间内导致亚马逊的ElastiCache redis实例崩溃。


2
Redis内置了保护机制,允许用户使用配置文件中的maxmemory选项设置内存使用的最大限制,从而限制Redis可以使用的内存。如果达到此限制,Redis将开始回复写命令的错误(但仍将接受只读命令),或者您可以在使用Redis进行缓存时配置它以在达到最大内存限制时驱逐键。如果您计划将Redis用作LRU缓存,则我们有文档可供参考。链接 - StefanNch
8
@StefanNch,redis的“maxmemory”选项没有考虑内部内存碎片化问题。请参见我上面的评论以获取详细信息——我描述的问题是在启用内存限制选项的“Redis作为LRU缓存”页面中看到的。另一方面,memcached采用不同的方法来避免内存碎片化问题,因此它的内存限制更加“硬”。 - artyom

46

Memcached擅长作为一个简单的键值存储器,并且擅长于处理键值对=>字符串。这使得它非常适合用于会话存储。

Redis则擅长于处理键值对=>某些对象。

实际上,这取决于您将要放入其中的内容。就性能而言,据我了解,它们相当平均。

如果您找到一些客观的基准测试,请祝你好运,如果您找到了,请友情发送给我。


2
在我看来,Redis哈希数据类型比将会话变量序列化为memcached字符串更有意义。 - Carl Zulauf
6
如果您在意用户体验,请勿将您的会话存入缓存中。http://dormando.livejournal.com/495593.html - sleblanc
4
从理论上讲,Redis 不应该有这个问题,因为它具有磁盘持久性。 - haknick
2
@sebleblanc,Memcache在会话存储方面仍然很好,您可能实现得不好。是的,驱逐是一个问题,但并非无法克服,而且如果您不担心驱逐,这也不是Memcache的问题。我相信大多数Memcache会话解决方案都使用cookie作为备份。 - Erik Petersen
11
“不要将您的会话存储在缓存中”这句话是误导性的。你的意思是“不要仅仅将您的会话存储在缓存中”。任何只在内存缓存中存储重要数据的人应该立即被解雇。 - Jay
显示剩余4条评论

37

如果您不介意一种粗俗的写作风格,Systoilet博客上的Redis与Memcached的比较从可用性角度来看值得一读,但在得出性能结论之前,请务必阅读评论中的回复,因为存在一些方法论问题(单线程忙循环测试),并且自该文章撰写以来,Redis已经进行了一些改进。

没有混淆事情的基准链接是不完整的,因此还请查看Dormondo的LiveJournalAntirez Weblog上的一些相互矛盾的基准测试结果。

编辑 -- 正如Antirez指出的那样,Systoilet分析相当不明智。即使超越了单线程缺陷,这些基准测试中许多性能差异都可以归因于客户端库而不是服务器吞吐量。 Antirez Weblog中的基准测试确实呈现了更加公正的比较。


9
「Redis vs Memcached」的基准测试设计有缺陷。http://oldblog.antirez.com/post/redis-memcached-benchmark.html - App Work
28
你没有开玩笑,这确实很粗俗。 - ocodo
1
此外,它是2010年的过时博客。 - Siddharth

24

我在实现缓存代理时使用了memcached和redis,让我与您分享我在哪里使用了什么以及背后的原因...

Redis >

1)用于对缓存内容进行索引,跨集群。我有超过十亿个键分布在redis集群中,redis响应时间相当低且稳定。

2)基本上,它是一个键/值存储,所以无论在应用程序的哪个地方您有类似的东西,都可以使用redis。

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

Memcache >

1)是一种优化的内存,可用作缓存。我用它来存储缓存内容,这些内容非常频繁地被访问(每秒50次),大小小于1 MB。

2)我只分配了16 GB中的2 GB给memcached,而且只有在单个内容大小大于1MB时才这样做。

3)随着内容接近极限,我偶尔会观察到更高的响应时间统计数据(不适用于redis)。

如果你想要整体的经验,Redis比Memcached更好,因为它易于配置,具有稳定的鲁棒特性。

此外,这里有一份基准测试结果,链接在这里,以下是一些亮点,

enter image description here

enter image description here

希望对您有所帮助!


15

测试。运行一些简单的基准测试。很长一段时间我认为自己是一只老派的犀牛,因为我主要使用memcached,而把Redis看作是新生事物。

在我现任公司中,Redis被用作主要缓存。但当我深入了解了一些性能统计并开始简单测试时,Redis在性能方面与MySQL相比,表现相似或者稍微一点。

虽然Memcached过于简单,但完全击败了Redis。它的扩展性要好得多:

  • 针对更大的值(需要改变slab大小,但有效)
  • 针对多个并发请求

此外,我的观点是,Memcached的驱逐策略实现得更好,可以在处理超出缓存容量的数据时,保持平均响应时间的稳定性。

一些基准测试揭示,在我们的情况下,Redis表现非常差。我相信这与许多变量有关:

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

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


请解释什么是“比MySQL略慢”。 - Anirudha Gupta
说实话,我手头没有这个基准数据,但那个特定的案例涉及了很多读写操作。 - mdomans

13
另一个好处是,缓存场景下 memcache 的行为非常清晰可见,而 redis 通常用作持久化数据存储,尽管可以配置其行为与 memcached 相同,即在达到最大容量时驱逐最近最少使用的项目。
我曾经参与开发的一些应用程序同时使用这两种技术以明确我们打算如何处理数据-将东西放入 memcache 中,编写代码来处理不存在的情况 - 将东西放入 redis 中,我们依赖它存在。
除此之外,Redis 通常被认为在大多数用例中都更加优秀,因为其功能更加丰富,从而更加灵活。

10

如果我们说Redis是(缓存+数据结构)的组合,而Memcached只是一种缓存,这并不算错。


1
这是一个好答案 - Laravel使用Redis作为缓存和数据存储机制。 - Miroslav Trninic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接