做者:刘旭晖 Raymond 转载请注明出处redis
Email:colorant at 163.com算法
BLOG:http://blog.csdn.net/colorant/数据库
Memcached和Redis做为两种Inmemory的key-value数据库,在设计和思想方面有着不少共通的地方,功能和应用方面在不少场合下(做为分布式缓存服务器使用等) 也很类似,在这里把二者放在一块儿作一下对比的介绍缓存
基本架构和思想服务器
首先简单介绍一下二者的架构和设计思路网络
Memcached数据结构
Memcached采用客户端-服务器的架构,客户端和服务器端的通信使用自定义的协议标准,只要知足协议格式要求,客户端Library能够用任何语言实现。架构
从用户的角度来讲,服务器维护了一个键-值关系的数据表,服务器之间相互独立,互相之间不共享数据也不作任何通信操做。客户端须要知道全部的服务器,并自行负责管理数据在各个服务器间的分配。分布式
在服务器端,内部的数据存储,使用基于Slab的内存管理方式,有利于减小内存碎片和频繁分配销毁内存所带来的开销。各个Slab按需动态分配一个page的内存(和4Kpage的概念不一样,这里默认page为1M),page内部按照不一样slab class的尺寸再划分为内存chunk供服务器存储KV键值对使用memcached
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协议的项目实现了数据的持久化,例如memcacheDB使用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技术
这两种方式均可以有效地减小网络通信开销,增长数据吞吐率
对于KV的操做,Memcached和Redis都支持Multiple的Get和Set命令(Memcached的Multiple Set命令貌似只在二进制的协议中支持),这一样有利于性能的提高
实际性能方面,网上有不少测试比较,给出的结果各不相同,这无疑和各类测试的测试用例,测试环境,和测试时具体使用的客户端Library实现有关。可是整体看下来,比较靠谱的结论是在kv类操做上,二者的性能接近,Memcached的结构更加简单,理论上应该会略微快一些。
集群
memcached的服务器端互相彻底独立,客户端一般经过对键值应用Hash算法决定数据的分区,为了减小服务器的增减对Hash结果的影响,致使大面积的缓存失效,多数客户端实现了一致性hash算法
Redis计划在服务器端内建对集群的支持,可是目前代码还处于alpha阶段(貌似已经Design了两三年了?)在此以前,一样能够认为每一个Redis服务器实例相互之间是彻底独立的,须要依靠客户端处理分区算法和可用服务器列表管理的工做。
Redis官方推荐的用于Sharding的客户端程序库是Twitter的开源项目 Twemproxy, Twemproxy同时支持Memcached和Redis的文本通信协议。
须要注意的是,Redis的许多命令在集群环境下是不能正确运行的,例如set的交集,以及跨节点的事务操做等等,由于目前的Redis集群设计,根本目标也就是服务器之间互相汇报一下存活状态,以及对数据作荣誉备份平衡负载等而已,本质上对数据的跨节点操做并不提供任何额外支持,因此在数据服务的层面上来讲,各个服务器依旧是彻底独立的。
这些操做若是必定要实现,固然能够经过客户端代码来实现(效率有多高且不说),相似的问题memcached集群固然也会赶上,可是本来memcached就不支持复杂的操做和数据类型,许多运算逻辑本来就是由客户端代码或应用程序本身处理的。
MR类批处理应用
提供指定范围的遍历操做,是支持相似MapReduce这样的批处理应用逻辑的关键之一,可是要在基于hash方式存储的数据结构的基础上提供这样的支持并不容易(或者说要实现高效的范围或遍历操做并不容易)
Redis支持Scan操做用于遍历数据集,这一操做基于其内部数据结构及实现的限制,能够保证在Scan开始时的全部数据都能被获取到,可是不能保证不返回重复的数据,这须要由客户端来检查,或者客户端对此无所谓。Scan操做还支持Match条件用来过滤键值,虽然存在必定的局限性,例如match条件的比较是在获取数据以后再执行的,效率是一个问题,更明显的问题是不能保证每次scan的iterate过程都能返回一样数量的有效数据。
对于范围操做,Redis的Ordered Set支持在插入时指定数据的分数(Score)用于排序,然后支持在指定Score范围内的各类操做,虽然因为不支持基于字符串的或自定义的基准的Range操做,这样的范围操做应用起来有很大的局限性(或者说须要知足特定的应用模式),可是仍是比没有好了
Memcached核心协议自己不支持任何范围类的操做,也没有对遍历操做的支持,甚至不存在官方合法的列举全部Key的操做,这固然很大程度上源于其设计思想和精简的架构
不过仍是有一些兼容memcached协议的服务器实现了范围类操做,具体格式能够参考 https://code.google.com/p/memcached/wiki/RangeOps 所建议的标准
此外Redis的Hashes数据结构,在必定程度上能够知足获取特定子集数据的应用逻辑需求。
综上来讲,若是要实现相似HBase支持的scan操做,不管是Redis仍是memcached都没法作到,可是对于Redis来讲,可否用于批处理类应用,不能一律而论,取决于具体的数据的格式逻辑和使用方式。经过适当的调整应用程序使用数据的方式,仍是有可能在必定程度上实现对MR类批处理,或范围查询类应用逻辑的支持的。而对于键值分布在一个较大的连续空间,数量不肯定,同时又没法很好的映射为数值进而使用ordered set来处理的这样一些数据结构,应该仍是很难高效的分区遍历的