对比
Redis和Memcached都能用于数据缓存,那这两种缓存服务在实际应用中该如何选择?Redis除了有更多的数据结构,在很多方面还是和Memcached不一样。我们在选择缓存服务时,通常需要考虑以下几点:
- 功能
- 速度
- 内存使用
- 缓存持久化
- 集群扩展
功能对比
Memcached只支持简单的key/value存储,并且存储的value只能是字符串,如果是整数形式字符串,还能对其进行简单的加减操作。
对于Redis,不仅在功能上能完全替代Memcached,还支持多种数据结构的存储:
除了支持更多的数据结构,Redis还提供了多种特性,比如发布订阅、事务、持久化、内置Lua解释器等。
在功能上,Redis要比Memcached丰富的多,同时 Redis文档 也比 Memcached文档 更加完善。
速度对比
因为都是数据都放在内存中,所以Redis和Memcached的读写速度都非常快。网络上有各种各样的benchmark,但是由于测试机器、版本、数据等等因数影响,测试结果不尽相同,但是性能差别极其微小。Redis和Memcached的性能差别可能是由于采用不同的I/O模型设计所导致的:
Memcached
Memcached采用的是多线程,基于libevent实现事件驱动,使用one loop per thread模型,监听线程将接收到的请求分发给各个worker线程处理。多线程模型能够充分的利用多核,但是同时引入了线程同步、锁等性能损耗。
Redis
Redis使用的是单线程IO复用模型,采用事件驱动方式处理请求。因为单线程,所以一个Redis进程并不能利用多核,但是可以通过启动多个Redis实例来利用多核。对于单纯的IO操作,处理速度非常快,但是一旦进行CPU计算(排序、聚合等),可能会影响吞吐量,因为CPU计算时,并不能进行事件IO调度。
一般来说,两者都足够快,性能瓶颈往往在于网络传输以及带宽限制。
内存使用对比
因为频繁调用原始的malloc/free很容易造成内存碎片导致无法重新利用,而且不匹配的malloc/free容易造成内存泄露。所以为了提高内存使用效率,Memcached和Redis都实现了自己的一套内存管理方案。
Memcached
Memcached使用Slab Allocation机制来管理内存。关于Slab Allocation机制,有很多文章已经介绍的很清楚了,其主要思想就是:预先将申请的内存空间划分为一系列的Slab,每个Slab只负责一定范围大小数据的存储。如果需要申请内存,那么每次申请的大小为一个Page,申请后会将这个Page切分成多个Chunk,实际数据存储在Chunk中。这样不会造成内存碎片,但是数据大小比Chunk小时,会造成空间浪费。
Memcached使用惰性过期策略,并不会到期就立即清理过期数据,而是当访问该数据时进行检查。或者当内存分配失败后,使用LRU算法来淘汰数据。内存一旦分配,Memcached便不会对其进行回收,而是在同一个Slab中重复利用。因为Memcached不回收内存,所以即使所有数据都过期,对Memcached进行Flush操作,其占用的系统内存并不会减少。
Redis
Redis使用jemalloc来进行内存分配,在减小内存碎片方面要比malloc/free做的更好。相比于Memcached,Redis的内存管理要简单得多,在需要时Redis就会申请内存,数据被清理时就会释放,所以在一定程度上会存在内存碎片。好处是清理后的内存会返还给操作系统,不会出现Memcached那种内存只增不减的情况。
当开启了Redis的虚拟内存(vm)后,如果物理内存使用量超过了最大限制,将引起swap操作,把一定的数据交换到磁盘上,当需要这些数据的时候,再从磁盘中取出放入内存里。内存中始终会保存所有的key信息,swap时会计算出哪些key对应的value需要进行交换。这个特性使得Redis可以保存超过机器内存大小的数据,但同时频繁的swap以及从磁盘读取会对其性能造成影响。
因为内存管理的实现不同,在内存使用上,Memcached和Redis可以说是各有优劣。最直观的特点就是,操作系统分配给Memcached的内存不会被释放,Memcached会一直重复利用这些内存,而Redis则会随着数据的失效将内存返还给操作系统。但是随着内存分配次数越来越多,Redis会造成内存碎片,使得物理内存占用一直增大,这时可能需要重启Redis来进行内存的重新分配。
缓存持久化对比
一旦重启缓存服务,Redis默认优先通过AOF重放来恢复缓存,仅仅会丢失很小一部分数据。而Memcached中的数据完全丢失,无法恢复。所以在缓存持久化方面,Redis完胜Memcached。Redis提供了两种持久化方式,RDB和AOF,可以根据业务需要来选择,也可以同时开启。而Memcached则没有原生支持持久化,而是需要依赖一些第三方的工具实现。
集群扩展对比
Memcached和Redis都能以分布式集群的形式扩展存储能力,但是在实现上有很大的不同。
Memcached
Memcached服务节点之间不支持相互通信,所以对于Memcached服务器来说,不支持数据共享机制。Memcached的分布式集群只能由客户端实现的,在获取数据前,客户端使用一定的路由算法(通常是一致性哈希算法)计算出数据所在的存储节点,然后向该节点发送相应的操作请求。
Redis
Redis服务器之间利用分片和主从机制来构造分布式集群。一个Redis集群正常工作至少需要三个主节点,主节点相互通信,确定各自负责的数据分片。主节点各自拥有冗余的从节点,从节点会复制对应主节点的数据,当主节点不可用时,就会在相应从节点中提升一个成为主节点,保证单点故障时整个集群的可用性。
为了保证主节点的响应性能,Redis集群不保证数据的强一致性:执行写命令后,主节点立即返回,数据复制到从节点的操作是异步的,此时如果获取该数据,就可能出现取不到的情况。
扩容简单、易部署是Memcached集群的特点。因为Memcached服务器之间不会互相通信,所以Memcached集群可以做到几乎无限制的线性伸缩,利用多台低配机器也能达到很好的性能效果。利用客户端实现的一致性hash路由算法以及引入虚拟节点,增减服务器也不会对当前缓存命中率有较大的影响。但是一旦出现单点故障,因为没有备份机制,缓存的读写都会出现问题,压力转移到数据库,引起性能甚至更严重的问题。
Redis集群在扩容、部署方面相比于Memcached就复杂了许多。Redis集群增减主节点都会引起数据的重新分片,如果此时集群正在服务,可能会带来性能上的开销。但是因为主从机制,以及从节点提升容灾,遇到单点故障时也能保证服务的可用性。
总结
总结来看,Memcached对比Redis并没有什么特别的优势,而且Redis还提供了更多的特性,以及更高的可用性和容灾策略,一般来说,选择Redis往往是没错的。但是工具的选择依赖于业务,如果在内存使用率、集群扩容等方面有着特殊的要求,Memcached可能要比Redis适合。