memcached redis 对比分析

简介

memcached和redis都属于内存(memory)键-值(key-value)数据库,在设计和思想上有许多相同之处,功能和应用在很多场合(如分布式缓存服务)也相似。它们都从属于数据库解决方案中的nosql家族,由于两者都将数据存储在内存中,自然而然,它们都是非常理想的缓存实现方案。

memcached最初是由Brad Fitzpatrick于2003年开发而成。而redis则由Salvatore Sanfilippo于2009年创建,它本身也从memcached上吸取借鉴大量宝贵经验教训,被称为“强化版memcached”。确实,redis在功能多样性方面要胜过memcached,虽然强大且更具灵活性,但复杂程度也比memcached更甚。


基本架构和思想

两者的架构和设计思想

memcached

memcached采用客户端-服务器(C/S)的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式要求,客户端Library可以用任何语言实现。

从用户的角度来说,服务器维护了一个键-值关系的数据表,服务器之间相互独立,互相之间不共享数据也不做任何通讯操作。也就是说,memcached本身不支持分布式扩展。客户端需要知道所有的服务器,并自行负责管理数据在各个服务器间的分配。

在服务器端,内部的数据存储,使用基于Slab的内存管理方式,有利于减少内存碎片和频繁分配销毁内存所带来的开销。各个Slab按需动态分配一个page的内存(和4Kpage的概念不同,这里默认page为1M),page内部按照不同slab class的尺寸再划分为内存chunk供服务器存储KV键值对使用。

memcached的基本应用模型:

redis

redis的基本应用模式和上图memcached的基本相似,不难发现网上到处都是关于redis是否可以完全替代memcached使用的问题。

redis内部的数据结构最终也会落实到key-value对应的形式,不过从暴露给用户的数据结构来看,要比memcached丰富,除了标准的通常意义的键值对,redis还支持List,Set, Hashes,Sorted Set等数据结构。


基本命令

memcached的命令或者说通讯协议非常简单,server所支持的命令基本就是对特定key的添加,删除,替换,原子更新,读取等,具体包括 set, get, add, replace, append, inc/dec 等等。

memcached的通讯协议包括文本格式和二进制格式,用于满足简单网络客户端工具(如telnet)和对性能要求更高的客户端的不同需求。

redis的命令在kv(string类型)上提供与memcached类似的基本操作,在其它数据结构上也支持基本类似的操作(当然还有这些数据结构所特有的操作,如set的union,list的pop等)而支持更多的数据结构,在一定程度上也就意味着更加广泛的应用场合

除了多种数据结构的支持,redis相比memcached还提供了许多额外的特性,比如subscribe/publish命令,以支持发布/订阅模式这样的通知机制等等,这些额外的特性同样有助于拓展它的应用场景。

redis的客户端-服务器通讯协议完全采用文本格式(在将来可能的服务器间通讯会采用二进制格式)。


事务

redis通过multi / watch / exec等命令可以支持事务的概念,原子性的执行一批命令。在2.6以后的版本中由于添加了对script脚本的支持,而脚本固有的是以transaction事务的方式执行的,并且更加易于使用,所以不排除将来取消multi等命令接口的可能性。

memcached的应用模式中,除了increment/decrement这样的原子操作命令,不存在对事务的支持。


数据备份,有效性,持久化等

memcached不保证存储的数据的有效性,slab内部基于LRU也会自动淘汰旧数据,客户端不能假设数据在服务器端的当前状态,这应该说是memcached的feature设定,用户不必太多关心或者自己管理数据的淘汰更新工作,当然是否适合你的应用,取决于具体的需求,它也可能成为你需要精确自行控制cache生命周期的一个障碍。

memcached也不做数据的持久化工作,但是有许多基于memcached协议的项目实现了数据的持久化,例如memcache DB使用BerkeleyDB进行数据存储,但本质上它已经不是一个cache server,而只是一个兼容memcached的协议key-valueData Store了

redis可以以master-slave的方式配置服务器,slave节点对数据进行replica备份,slave节点也可以充当read only的节点分担数据读取的工作

redis内建支持两种持久化方案,snapshot快照和AOF增量Log方式。快照顾名思义就是隔一段时间将完整的数据dump下来存储在文件中。AOF增量Log则是记录对数据的修改操作(实际上记录的就是每个对数据产生修改的命令本身),两种方案可以并存,也各有优缺点,具体参见http://redis.io/topics/persistence

以上Redis的数据备份持久化方案等,如果不需要,为了提高性能,也完全可以Disable


性能

memcached

memcached自身并不主动定期检查和标记哪些数据需要被淘汰,只有当再次读取相关数据时才检查时间戳,或者当内存不够使用需要主动淘汰数据时进一步检查LRU数据。

redis

redis为了减少大量小数据CMD操作的网络通讯时间开销 RTT (Round Trip Time),支持pipeline和script技术。

所谓的pipeline就是支持在一次通讯中,发送多个命令给服务器批量执行,带来的代价是服务器端需要更多的内存来缓存查询结果。

redis内嵌了LUA解析器,可以执行lua脚本,脚本可以通过eval等命令直接执行,也可以使用script load等方式上传到服务器端的script cache中重复使用。

这两种方式都可以有效地减少网络通讯开销,增加数据吞吐率。

对于KV的操作,memcached和redis都支持multiple的get和set命令(memcached的multiple set命令貌似只在二进制的协议中支持),这同样有利于性能的提升。

实际性能方面,网上有很多测试比较,给出的结果各不相同,这无疑和各种测试的测试用例,测试环境,和测试时具体使用的客户端Library实现有关。但是总体看下来,比较靠谱的结论是在kv类操作上,两者的性能接近,memcached的结构更加简单,理论上应该会略微快一些。


集群

memcached的服务器端互相完全独立,客户端通常通过对键值应用hash算法决定数据的分区,为了减少服务器的增减对hash结果的影响,导致大面积的缓存失效,多数客户端实现了一致性hash算法。

redis计划在服务器端内建对集群的支持,在此之前,同样可以认为每个redis服务器实例相互之间是完全独立的,需要依靠客户端处理分区算法和可用服务器列表管理的工作。

redis官方推荐的用于sharding的客户端程序库是Twitter的开源项目Twemproxy, Twemproxy同时支持Memcached和Redis的文本通讯协议。

需要注意的是,redis的许多命令在集群环境下是不能正确运行的,例如set的交集,以及跨节点的事务操作等等,因为目前的redis集群设计,根本目标也就是服务器之间互相汇报一下存活状态,以及对数据做荣誉备份平衡负载等而已,本质上对数据的跨节点操作并不提供任何额外支持,所以在数据服务的层面上来说,各个服务器依旧是完全独立的。

这些操作如果一定要实现,当然可以通过客户端代码来实现(效率有多高且不说),类似的问题memcached集群当然也会遇上,但是原本memcached就不支持复杂的操作和数据类型,许多运算逻辑原本就是由客户端代码或应用程序自己处理的。


如何选择

何时应该使用memcached

相对memcached而言,redis的面世时间更晚且具备更多功能,因此开发人员通常将其视为默认性首选方案。不过有两类特殊场景仍然是memcached的一家天下。首先就是对小型静态数据进行缓存处理,最具代表性的例子就是HTML代码片段。memcached的内部内存管理机制虽然不像redis的那样复杂,但却更具实际效率——这是因为memcached在处理元数据时所消耗的内存资源相对更少。作为memcached所支持的惟一一种数据类型,字符串非常适合用于保存那些只需要进行读取操作的数据,因为字符串本身无需进行进一步处理。

除此之外,memcached在横向扩展方面也比redis更具优势。由于其在设计上的思路倾向以及相对更为简单的功能设置,memcached在实现扩展时的难度比redis低得多。不过根据我们了解到的情况,目前已经有多种经过测试且切实有效的方案能够将redis扩展至多台服务器之上,而其即将发布的3.0版本(感兴趣的朋友可以点击此处查看其候选版本说明)将包含专门针对横向扩展场景的内置集群化机制。

何时应该使用redis

除非大家需要考虑某种限定性条件(例如处理传统应用程序)对于memcached的特殊依赖性,或者自己的实际用例属于前面提到的两类场景中的一种,否则请直接选择redis并加以运用。凭借着redis所带来的卓越缓存方案,我们将拥有强大的处理能力——例如对缓存内容及持久性进行细节调整的能力——以及出色的整体执行效率。

redis几乎在缓存管理工作中的每一个侧面都表现出显而易见的优越性。这套缓存方案采用所谓数据回收机制,能够将陈旧数据从内存中删除以提供新数据所必需的缓存空间。memcached的数据回收机制使用的是LRU(即最低近期使用量)算法,而且往往会比较武断地直接删除掉与新数据体系相近的原有内容。相比之下,redis允许用户更为精准地进行细化控制,利用六种不同回收策略确切提高缓存资源的实际利用率。redis还采用更为复杂的内存管理与回收对象备选方案。

redis还能为我们带来最大程度的灵活性空间,从而保证管理员在打理缓存对象时拥有充裕的施展平台。在这方面,memcached将键名限制在250字节,值也被限制在不超过1MB,且只适用于普通字符串。相比之下,redis则将键名与值的最大上限各自设定为512MB,且支持二进制格式。redis支持六种数据类型,因此能够更加智能地对数据进行缓存处理及操作,这相当于为应用程序开发人员敞开了一道通往无尽可能性的大门。

相对于将对象保存为序列化字符串,redis允许开发人员以散列方式将对象域及值加以保存,并利用单一键对其进行管理。redis散列机制的存在保证开发人员无需经历获取完整字符串、反序列化、更新值、对象重新序列化并在每次值更新后利用其替代缓存内完整字符串这一系列复杂的流程——这也意味着资源消耗量得以降低、性能表现迎来显著提升。redis所支持的其它数据类型,例如lists以及sets——也可被用于实现更加复杂的缓存管理模式。

redis的另一大重要优势在于,它所保存的数据具备透明化特性,也就是说服务器能够直接对这些数据进行操作。redis当中提供160多种可用命令,其中大部分用于实现数据处理操作并通过服务器端脚本将逻辑嵌入至数据存储体系当中。这些内置命令及用户脚本带来了极大的灵活性优势,足以帮助大家直接在redis内部完成数据处理任务——而不必将数据在网络中的其它专门处理系统之间来回移动。

redis还提供可选而且能够具体调整的数据持久性方案,其设计目的在于在发生规划内停机或者计划外故障之后对缓存内容进行重新引导。虽然我们更倾向于强调缓存内数据的易失性与暂时性,但将数据在磁盘中加以持久保存在某些缓存场景当中仍然极具现实意义。这种机制能够在设备重启之后快速将保存在磁盘上的数据重新载入至缓存当中,从而大大缩短缓存预热周期并根据主数据存储内容对当前缓存内容进行重新评估。

最后但也同样重要的一点是,redis能够提供复制功能。复制功能旨在帮助缓存体系实现高可用性配置方案,从而在遭遇故障的情况下继续为应用程序提供不间断的缓存服务。很明显,一套成熟的缓存方案应该能够在应用程序发生故障时略微甚至完全不给用户体验或者应用程序性能表现带来任何影响,而这种对缓存内容及服务可用性的有力保障在大多数情况下也成为缓存解决方案的一大主要优势。

小结

redis的作者Salvatore Sanfilippo曾经对这两种基于内存的数据存储系统进行过比较,总体来看还是比较客观的,现总结如下:

  1. 性能对比:由于redis只使用单核,而memcached可以使用多核,所以平均每一个核上redis在存储小数据时比memcached性能更高。而在100k以上的数据中,memcached性能要高于redis,虽然redis最近也在存储大数据的性能上进行优化,但是比起memcached,还是稍有逊色。
  2. 内存使用效率对比:使用简单的key-value存储的话,memcached的内存利用率更高,而如果redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于memcached。另外,memcached使用预分配的内存池的方式,带来一定程度的空间浪费 并且在内存仍然有很大空间时,新的数据也可能会被剔除,而redis使用现场申请内存的方式来存储数据,不会剔除任何非临时数据 redis更适合作为存储而不是cache。
  3. redis支持服务器端的数据操作:redis相比memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果需要缓存能够支持更复杂的结构和操作,那么redis会是不错的选择。

另外,贴一些前辈们使用redis的经验和教训:

  1. 要进行master-slave配置,出现服务故障时可以支持切换。
  2. 在master侧禁用数据持久化,只需在slave上配置数据持久化。
  3. 物理内存+虚拟内存不足,这个时候dump一直死着,时间久了机器挂掉。这个情况就是灾难。
  4. 当redis物理内存使用超过内存总容量的3/5时就会开始比较危险了,就开始做swap,内存碎片大。
  5. 当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间。
  6. redis与DB同步写的问题,先写DB,后写redis,因为写内存基本上没有问题。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容

  • redis和memcached的区别 1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过...
    代码技巧阅读 7,544评论 1 9
  • 转载 https://www.jianshu.com/p/e94fa7340923 简介 memcached和re...
    raincoffee阅读 532评论 0 6
  • 一、学习与实践 1.付出不亚于任何人的努力 2.要谦虚,不要骄傲 3.要每天反省 4.活着,就要感谢 5.积善行,...
    杨柳_9137阅读 46评论 0 0
  • 我……在黑暗中 在这伸手不见五指黑夜里 我踉跄而行 我的心被恐惧包裹 我希望我可以看到光明 光明啊,你在哪里 请你...
    子青玄阅读 342评论 0 2
  • 我想了很久,一直不明白一件事,人活着为了什么?累成狗都不知道停下来歇会,有时候,真不如狗,这样说,貌似是很不地道,...
    d3a17469fa4f阅读 99评论 0 3