前言我们都知道Redis和Memcached都是内存数据库,访问速度非常快。但是在我们的开发过程中,我们该如何选择这两种内存数据库呢?他们的优缺点是什么?为什么现在Redis比Memcached更受欢迎?在本文中,我们将从各个方面比较这两种内存数据库的差异,以便您在使用时做出最符合您业务需求的选择。分析它们的区别,我们主要从以下几个方面进行比较:线程模型数据结构退出策略管道和事务持久化高可用性集群线程模型要谈性能,就必须要分析它们的服务模型。Memcached采用多线程模型处理请求,基于IO多路复用技术,主线程收到请求后将请求分发给子线程。这样做的好处是,当一个请求处理起来比较耗时时,不会影响其他请求的处理。当然缺点是在CPU的多线程切换中势必会有性能损失。同时,多线程在访问共享资源时必须加锁,这也会在一定程度上降低性能。Redis也采用了IO多路复用技术,但是它采用单线程模型来处理请求,从接收请求到处理数据都在一个线程中进行。这意味着用Redis,一旦一个请求处理时间过长,整个Redis就会被阻塞,直到请求处理完毕返回,才能处理下一个请求。使用Redis时,必须避免复杂的耗时操作。单线程的优点是CPU上下文切换损失少,没有多线程访问资源的锁竞争,缺点是不能发挥CPU多核的性能优势。由于Redis是内存数据库,访问速度非常快,所以它的性能瓶颈不是CPU,而是内存和网络带宽,这也是笔者采用单线程模型的主要原因。同时,单线程对程序开发非常友好,调试起来也非常方便。开发多线程程序必然会增加调试的难度。所以,当我们业务使用的关键数据比较大的时候,Memcached的访问性能要优于Redis。如果关键数据比较小,两者区别不大。”严格来说,Redis的单线程是指处理请求的线程。它还有其他线程在工作,比如使用其他线程异步处理耗时任务。Redis6.0进一步改进了多线程。在Multi-line在接收和发送请求时使用,进一步提高了处理性能数据结构Memcached支持的数据结构非常简单,只支持字符串类型的操作。并且值的大小限制必须小于1MB,并且过期时间不能超过30天。Redis支持的数据结构非常丰富。除了常用的数据类型string、list、hash、set、zset外,还可以使用geo、hyperLogLog数据类型。使用Memcached时,我们只能将数据序列化,写入Memcached中。然后从Memcached中读取数据,再反序列化成我们需要的格式,只能“整体存取”。而且Redis可以针对不同的数据结构采用不同的操作方式,非常灵活。list:可以很方便的构建一个链表,也可以作为队列hash:灵活操作我们需要的字段,实现“全存零取”、“零存全取”、“零存零取”set:构建一个非volatile的重复集合,方便进行求并运算zset:构建一个排行榜,或者一个带权重的列表geo:用于地图相关的业务,识别两个位置的坐标,并计算它们的距离hyperLogLog:使用非常小的内存来计算UV总之,Redis这几年在内存数据库领域大放异彩,正是因为它提供了如此丰富的数据结构,为我们的业务发展提供了极大的便利。淘汰策略Memcached必须设置整个实例的内存上限。当数据达到上限时,会触发LRU淘汰机制,先淘汰不常用的数据。但其数据淘汰机制存在一些问题:新写入的数据可能会先被淘汰。这个问题主要是自身的内存管理设计机制造成的。Redis没有限制,必须设置内存上限。如果内存足够,Redis可以使用足够的内存。同时Redis提供了多种淘汰策略:volatile-lru:根据LRU机制从过期key中淘汰所有key-lru:根据LRU机制从所有key中淘汰volatile-random从key中随机淘汰keyvolatile-ttl:优先淘汰最近即将过期的keyvolatile-lfu:通过LFU机制淘汰所有key中的allkeys-lfu:通过LFU机制淘汰过期的key我们可以针对业务场景采用不同的数据淘汰策略。管道和事务Redis也支持管道功能。客户端一次性将多条命令打包发送给服务器,服务器依次处理客户端发送的命令。这样可以减少往返网络IO的次数,提供较高的访问性能。此外,它还支持交易。这里所说的事务并不是像MySQL那样严格的事务模型。这种事务模型是Redis独有的。一般事务将与管道一起使用。客户端一次性将多条命令打包发送给服务器,并标记这些命令必须严格按顺序执行,不能被其他客户端打断。在同时执行事务之前,客户端可以告诉服务端某个key稍后会执行相关的操作。如果其他客户端在该客户端操作key之前改变了key,那么当当前客户端执行这些命令时,整个事务操作将被放弃,以保证一致性。持久性Memcached不支持数据持久化。如果Memcached服务宕机,则该节点上的所有数据都将丢失。Redis支持数据持久化到磁盘,提供两种方式:RDB和AOF:RDB:将整个实例中的数据快照到磁盘,完全持久化AOF:将每次写命令持久化到磁盘,使用增量持久化Redis这两种方式配合相互完成数据完整性保证,最大限度地减少服务停机造成的数据丢失。高可用Memcached没有主从复制架构,只能部署在单节点上。如果一个节点宕机,该节点上的所有数据都将丢失。业务需要与这种情况兼容。当一个节点不可用时,将数据写入其他节点,减少对业务的影响。Redis具有主从复制架构。两个节点构成主从架构。slave可以实时同步master的数据,提高整个Redis服务的可用性。同时Redis还提供了哨兵节点。当主节点宕机时,会主动将从节点提升为主节点,继续提供服务。主从节点还可以提供读写分离功能,进一步提高程序访问的性能。集群式的Memcached和Redis都是由多个节点组成对外提供服务,但是它们的机制也不同。Memcached的集群是在客户端使用一致性哈希算法将数据发送到指定的节点。当一个节点宕机时,其他节点将共享该节点的请求。Redis集群利用每个节点维护一部分虚拟槽,通过key哈希计算,将key映射到具体的虚拟槽,槽再映射到具体的Redis节点。同时,每个Redis节点至少包含一个从节点,形成主从架构,进一步提高了每个节点的高可用性。添加或下线节点时,需要手动触发数据迁移,重新映射哈希槽。Redis官方的集群方案是Rediscluster,采用去中心化设计。此外,还有采用中心化代理设计的第三方集群解决方案,如Codis、Twemproxy。综上所述,从以上几个方面进行对比分析,总结如下表。#MemcachedRedis线程模型多线程单线程数据结构只支持string,值最大1M,过期时间不能超过30天string,list,hash,set,zset,geo,hyperLogLog淘汰策略LRULRU,LFU,random不支持其他策略管道和事务。不支持持久化。不支持高可用性。不支持主从复制+哨兵集群客户端一致性哈希算法。主从复制+哨兵+固定哈希槽。总体来说,Redis提供了非常丰富的Function,性能与Memcached基本持平,这也是近几年占据内存数据库头把交椅的原因。如果你的业务需要各种数据结构的支持,需要数据的高可用,那么选择Redis是比较合适的。如果你的业务很简单,只是简单的set/get,内存占用不高,那么简单的Memcached就够了。如果本文能给您带来工作效率上的小小提升,不妨阅读并转发,鼓励我写出更好的文章!
