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