Redis 和 Memcache 都是基于内存的数据存储系统。Memcached是高性能分布式内存缓存服务;Redis是一个开源的key-value存储系统。与Memcached相似,Redis将大部分数据存储在内存中,支持的数据类型包括:字符串、哈希 表、链表、等数据类型的相关操做。下面咱们来进行来看一下redis和memcached的区别redis
Redis的做者Salvatore Sanfilippo曾经对这两种基于内存的数据存储系统进行过比较:数据库
Redis支持服务器端的数据操做:Redis相比Memcached来讲,拥有更多的数据结构和并支持更丰富的数据操做,一般在Memcached里,你须要将数据拿到客户端来进行相似的修改再set回去。这大大增长了网络IO的次数和数据体积。在Redis中,这些复杂的操做一般和通常的GET/SET同样高效。因此,若是须要缓存可以支持更复杂的结构和操做,那么Redis会是不错的选择。数组
内存使用效率对比:使用简单的key-value存储的话,Memcached的内存利用率更高,而若是Redis采用hash结构来作key-value存储,因为其组合式的压缩,其内存利用率会高于Memcached。缓存
性能对比:因为Redis只使用单核,而Memcached可使用多核,因此平均每个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,可是比起Memcached,仍是稍有逊色。安全
具体为何会出现上面的结论,如下为收集到的资料:服务器
一、数据类型支持不一样网络
与Memcached仅支持简单的key-value结构的数据记录不一样,Redis支持的数据类型要丰富得多。最为经常使用的数据类型主要由五种:String、Hash、List、Set和Sorted Set。Redis内部使用一个redisObject对象来表示全部的key和value。redisObject最主要的信息如图所示:session
type表明一个value对象具体是何种数据类型,encoding是不一样数据类型在redis内部的存储方式,好比:type=string表明value存储的是一个普通字符串,那么对应的encoding能够是raw或者是int,若是是int则表明实际redis内部是按数值型类存储和表示这个字符串的,固然前提是这个字符串自己能够用数值表示,好比:”123″ “456”这样的字符串。只有打开了Redis的虚拟内存功能,vm字段字段才会真正的分配内存,该功能默认是关闭状态的。数据结构
1)String并发
经常使用命令:set/get/decr/incr/mget等;
应用场景:String是最经常使用的一种数据类型,普通的key/value存储均可以归为此类;
实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等操做时会转成数值型进行计算,此时redisObject的encoding字段为int。
2)Hash
经常使用命令:hget/hset/hgetall等
应用场景:咱们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,经过用户ID咱们但愿获取该用户的姓名或者年龄或者生日;
实现方式:Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如图所示,Key是用户ID, value是一个Map。这个Map的key是成员的属性名,value是属性值。这样对数据的修改和存取均可以直接经过其内部Map的Key(Redis里称内部Map的key为field), 也就是经过 key(用户ID) + field(属性标签) 就能够操做对应属性数据。当前HashMap的实现有两种方式:当HashMap的成员比较少时Redis为了节省内存会采用相似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
3)List
经常使用命令:lpush/rpush/lpop/rpop/lrange等;
应用场景:Redis list的应用场景很是多,也是Redis最重要的数据结构之一,好比twitter的关注列表,粉丝列表等均可以用Redis的list结构来实现;
实现方式:Redis list的实现为一个双向链表,便可以支持反向查找和遍历,更方便操做,不过带来了部分额外的内存开销,Redis内部的不少实现,包括发送缓冲队列等也都是用的这个数据结构。
4)Set
经常使用命令:sadd/spop/smembers/sunion等;
应用场景:Redis set对外提供的功能与list相似是一个列表的功能,特殊之处在于set是能够自动排重的,当你须要存储一个列表数据,又不但愿出现重复数据时,set是一个很好的选择,而且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的;
实现方式:set 的内部实现是一个 value永远为null的HashMap,实际就是经过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的缘由。
5)Sorted Set
经常使用命令:zadd/zrange/zrem/zcard等;
应用场景:Redis sorted set的使用场景与set相似,区别是set不是自动有序的,而sorted set能够经过用户额外提供一个优先级(score)的参数来为成员排序,而且是插入有序的,即自动排序。当你须要一个有序的而且不重复的集合列表,那么能够选择sorted set数据结构,好比twitter 的public timeline能够以发表时间做为score来存储,这样获取时就是自动按时间排好序的。
实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是全部的成员,排序依据是HashMap里存的score,使用跳跃表的结构能够得到比较高的查找效率,而且在实现上比较简单。
二、内存管理机制不一样
在Redis中,并非全部的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。当物理内存用完时,Redis能够将一些好久没用到的value交换到磁盘。Redis只会缓存全部的key的信息,若是Redis发现内存的使用量超过了某一个阀值,将触发swap的操做,Redis根据“swappability = age*log(size_in_memory)”计算出哪些key对应的value须要swap到磁盘。而后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis能够保持超过其机器自己内存大小的数据。固然,机器自己的内存必需要可以保持全部的key,毕竟这些数据是不会进行swap操做的。同时因为Redis将内存中的数据swap到磁盘中的时候,提供服务的主线程和进行swap操做的子线程会共享这部份内存,因此若是更新须要swap的数据,Redis将阻塞这个操做,直到子线程完成swap操做后才能够进行修改。当从Redis中读取数据的时候,若是读取的key对应的value不在内存中,那么Redis就须要从swap文件中加载相应数据,而后再返回给请求方。 这里就存在一个I/O线程池的问题。在默认的状况下,Redis会出现阻塞,即完成全部的swap文件加载后才会相应。这种策略在客户端的数量较小,进行批量操做的时候比较合适。可是若是将Redis应用在一个大型的网站应用程序中,这显然是没法知足大并发的状况的。因此Redis运行咱们设置I/O线程池的大小,对须要从swap文件中加载相应数据的读取请求进行并发操做,减小阻塞的时间。
对于像Redis和Memcached这种基于内存的数据库系统来讲,内存管理的效率高低是影响系统性能的关键因素。传统C语言中的malloc/free函数是最经常使用的分配和释放内存的方法,可是这种方法存在着很大的缺陷:首先,对于开发人员来讲不匹配的malloc和free容易形成内存泄露;其次频繁调用会形成大量内存碎片没法回收从新利用,下降内存利用率;最后做为系统调用,其系统开销远远大于通常函数调用。因此,为了提升内存的管理效率,高效的内存管理方案都不会直接使用malloc/free调用。Redis和Memcached均使用了自身设计的内存管理机制,可是实现方法存在很大的差别,下面将会对二者的内存管理机制分别进行介绍。
Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以彻底解决内存碎片问题。Slab Allocation机制只为存储外部数据而设计,也就是说全部的key-value数据都存储在Slab Allocation系统里,而Memcached的其它内存请求则经过普通的malloc/free来申请,由于这些请求的数量和频率决定了它们不会对整个系统的性能形成影响Slab Allocation的原理至关简单。 如图所示,它首先从操做系统申请一大块内存,并将其分割成各类尺寸的块Chunk,并把尺寸相同的块分红组Slab Class。其中,Chunk就是用来存储key-value数据的最小单位。每一个Slab Class的大小,能够在Memcached启动的时候经过制定Growth Factor来控制。假定图中Growth Factor的取值为1.25,若是第一组Chunk的大小为88个字节,第二组Chunk的大小就为112个字节,依此类推。
当Memcached接收到客户端发送过来的数据时首先会根据收到数据的大小选择一个最合适的Slab Class,而后经过查询Memcached保存着的该Slab Class内空闲Chunk的列表就能够找到一个可用于存储数据的Chunk。当一条数据库过时或者丢弃时,该记录所占用的Chunk就能够回收,从新添加到空闲列表中。
从以上过程咱们能够看出Memcached的内存管理制效率高,并且不会形成内存碎片,可是它最大的缺点就是会致使空间浪费。由于每一个Chunk都分配了特定长度的内存空间,因此变长数据没法充分利用这些空间。如图 所示,将100个字节的数据缓存到128个字节的Chunk中,剩余的28个字节就浪费掉了。
Redis的内存管理主要经过源码中zmalloc.h和zmalloc.c两个文件来实现的。Redis为了方便内存的管理,在分配一块内存以后,会将这块内存的大小存入内存块的头部。如图所示,real_ptr是redis调用malloc后返回的指针。redis将内存块的大小size存入头部,size所占据的内存大小是已知的,为size_t类型的长度,而后返回ret_ptr。当须要释放内存的时候,ret_ptr被传给内存管理程序。经过ret_ptr,程序能够很容易的算出real_ptr的值,而后将real_ptr传给free释放内存。
Redis经过定义一个数组来记录全部的内存分配状况,这个数组的长度为ZMALLOC_MAX_ALLOC_STAT。数组的每个元素表明当前程序所分配的内存块的个数,且内存块的大小为该元素的下标。在源码中,这个数组为zmalloc_allocations。zmalloc_allocations[16]表明已经分配的长度为16bytes的内存块的个数。zmalloc.c中有一个静态变量used_memory用来记录当前分配的内存总大小。因此,总的来看,Redis采用的是包装的mallc/free,相较于Memcached的内存管理方法来讲,要简单不少。
三、数据持久化支持
Redis虽然是基于内存的存储系统,可是它自己是支持内存数据的持久化的,并且提供两种主要的持久化策略:RDB快照和AOF日志。而memcached是不支持数据持久化操做的。
区别总结以下
一、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其余东西,例如图片、视频等等;
二、Redis不只仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;
三、虚拟内存--Redis当物理内存用完时,能够将一些好久没用到的value 交换到磁盘;
四、过时策略--memcache在set时就指定,例如set key1 0 0 8,即永不过时。Redis能够经过例如expire 设定,例如expire name 10;
五、分布式--设定memcache集群,利用magent作一主多从;redis能够作一主多从。均可以一主一从;
六、存储数据安全--memcache挂掉后,数据没了;redis能够按期保存到磁盘(持久化);
七、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后能够经过aof恢复;
八、Redis支持数据的备份,即master-slave模式的数据备份;
九、应用场景不同:Redis出来做为NoSQL数据库使用外,还能用作消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等。