的区别大吗 Redis 和 Memcached 只选一个做缓存咱们该选哪个

了解过两者的同窗有那么个大抵的印象:

1、redis与memcached相比,比仅支持繁难的key-value数据类型,同时还提供list,set,zset,hash等数据结构的存储;

2、redis支持数据的备份,即master-slave形式的数据备份;

3、redis支持数据的耐久化,可以将内存中的数据坚持在磁盘中,重启的时刻可以再次加载启动经常使用等等。

这仿佛看起来redis比memcached愈加牛逼一些,那么理想上是不是这样的呢?存在即正当,咱们来依据几个不同点来逐一比拟一下。

网络IO模型

memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络衔接,接受恳求后,将衔接形容字pipe传递给worker线程,启动读写IO,网络层经常使用libevent封装的事情库,多线程模型可以施展多核作用,然而引入了cache coherency和锁的疑问,比如:memcached最罕用的stats命令,实践memcached一切操作都要对这个全局变量加锁,启动技术等上班,带来了性能损耗。

redis经常使用复线程的IO复用模型,自己封装了一个繁难的AeEvent事情处置框架,关键成功了epoll, kqueue和select,关于单存只要IO操作来说,复线程可以将速度好处施展到***,然而redis也提供了一些繁难的计算配置,比如排序、聚合等,关于这些操作,复线程模型施加会重大影响全体吞吐量,CPU计算环节中,整个IO调度都是被阻塞的。

数据支持类型

memcached经常使用key-value方式存储和访问数据,在内存中保养一张渺小的HashTable,使得对数据查问的期间复杂度降落到O(1),保障了对数据的高性能访问。

正如开篇所说:redis与memcached相比,比仅支持繁难的key-value数据类型,同时还提供list,set,zset,hash等数据结构的存储;详细可以翻阅《Redis内存经常使用提升与存储》

内存治理机制

关于像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中,并不是一切的数据都不时存储在内存中的。这是和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文件中加载相应数据的读取恳求启动并发操作,缩小阻塞的期间。

Memcached经常使用预调配的内存池的方式,经常使用slab和大小不同的chunk来治理内存,Item依据大小选用适宜的chunk存储,内存池的方式可以省去放开/监禁内存的开支,并且能减小内存碎片发生,但这种方式也会带来必定水平上的空间糜费,并且在内存依然有很大空间时,新的数据也或许会被剔除,要素可以参考Timyang的文章:

Redis经常使用现场放开内存的方式来存储数据,并且很少经常使用free-list等方式来提升内存调配,会在必定水平上存在内存碎片,Redis跟据存储命令参数,会把带过时期间的数据独自寄存在一同,并把它们称为暂时数据,非暂时数据是永远不会被剔除的,即使物理内存不够,造成swap也不会剔除任何非暂时数据(但会尝试剔除局部暂时数据),这点上Redis更适宜作为存储而不是cache。

数据存储及耐久化

memcached不支持内存数据的耐久化操作,一切的数据都以in-memory的方式存储。

redis支持耐久化操作。redis提供了两种不同的耐久化方法来讲数据存储到硬盘外面,一种是快照(snapshotting),它可以将存在于某一时辰的一切数据都写入硬盘外面。另一种方法叫只追加文件(append-only file, AOF),它会在口头写命令时,将被口头的写命令复制到硬盘外面。

数据分歧性疑问

Memcached提供了cas命令,可以保障多个并发访问操作同一份数据的分歧性疑问。 Redis没有提供cas 命令,并不能保障这点,不过Redis提供了事务的配置,可以保障一串 命令的原子性,两边不会被任何操作打断。

集群治理不同

Memcached是全内存的数据缓冲系统,Redis只管支持数据的耐久化,然而全内存毕竟才是其高性能的实质。作为基于内存的存储系统来说,机器物理内存的大小就是系统能够容纳的***数据量。假设要求处置的数据量超越了单台机器的物理内存大小,就要求构建散布式集群来裁减存储才干。

Memcached自身并不支持散布式,因此只能在客户端经过像分歧性哈希这样的散布式算法来成功Memcached的散布式存储。下图给出了Memcached的散布式存储成功架构。当客户端向Memcached集群发送数据之前,首先会经过内置的散布式算法计算出该条数据的指标节点,而后数据会间接发送到该节点上存储。但客户端查问数据时,雷同要计算出查问数据所在的节点,而后间接向该节点发送查问恳求以失掉数据。

相较于Memcached只能驳回客户端成功散布式存储,Redis更倾向于在主机端构建散布式存储。***版本的Redis曾经支持了散布式存储配置。Redis Cluster是一个成功了散布式且准许单点缺点的Redis初级版本,它没有中心节点,具备线性可伸缩的配置。Redis Cluster的散布式存储架构,节点与节点之间经过二进制协定启动通讯,节点与客户端之间经过ascii协定启动通讯。在数据的搁置战略上,Redis Cluster将整个key的数值域分红4096个哈希槽,每个节点上可以存储一个或多个哈希槽,也就是说Redis Cluster支持的***节点数就是4096。Redis Cluster经常使用的散布式算法也很繁难:crc16( key ) % HASH_SLOTS_NUMBER。

为了保障单点缺点下的数据可用性,Redis Cluster引入了Master节点和Slave节点。在Redis Cluster中,每个Master节点都会有对应的两个用于冗余的Slave节点。这样在整个集群中,恣意两个节点的宕机都不会造成数据的无法用。当Master节点分开后,集群会智能选用一个Slave节点成为新的Master节点。

您可能还会对下面的文章感兴趣: