Memcached、Redis、MongoDB 的区别
优缺点
Memcached
优点:
- 可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS。适用于最大程度扛量。
- 支持直接配置为 session handle。
缺点:
- 只支持简单的 key/value 数据结构,不像 Redis 可以支持丰富的数据类型。
- 无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。
- 无法进行数据同步,不能将 Memcached 中的数据迁移到其他 Memcached 实例中。
- 内存分配采用 Slab Allocation 机制管理内存,value 大小分布差异较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题。需要用户注重value设计。
应用:
- 分布式缓存
- 数据库前段缓存
- 服务器间数据共享
Redis
优点:
- 支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基数估算)
- 支持持久化操作,可以进行 aof 及 rdb 数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。
- 支持通过 Replication 进行数据复制,通过 master-slave 机制,可以实时进行数据的同步复制,支持多级复制和增量复制,master-slave 机制是 Redis 进行 HA 的重要手段。
- 单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题。
- 支持 pub/sub 消息订阅机制,可以用来进行消息订阅与通知。
- 支持简单的事务需求,但业界使用场景很少,并不成熟。
缺点:
- 只能使用单线程,性能受限于 CPU 性能,故单实例 CPU 最高才可能达到 5-6w QPS 每秒。
- 支持简单的事务需求,但业界使用场景很少,并不成熟,既是优点也是缺点。
- 在 string 类型上会消耗较多内存,可以使用 dict(hash表)压缩存储以降低内存耗用。
- Memcached 和 Redis 都是 Key-Value 类型,不适合在不同数据集之间建立关系,也不适合进行查询搜索。比如 redis 的 keys pattern 这种匹配操作,对 redis 的性能是灾难。
应用:
- 热点数据的缓存
由于 Redis 访问速度块、支持的数据类型比较丰富,所以 Redis 很适合用来存储热点数据,另外结合
expire
,我们可以设置过期时间然后再进行缓存更新操作,这个功能最为常见,我们几乎所有的项目都有所运用。
- 限时业务的运用
Redis 中可以使用
expire
命令设置一个键的生存时间,到时间后 Redis 会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
- 计数器相关问题
Redis 由于
incrby
命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
- 排行榜相关问题
关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助 Redis 的 SortedSet 进行热点数据的排序。
在奶茶活动中,我们需要展示各个部门的点赞排行榜, 所以我针对每个部门做了一个 SortedSet,然后以用户的 openid 作为上面的 username,以用户的点赞数作为上面的 score,然后针对每个用户做一个 hash,通过
zrangebyscore
就可以按照点赞数获取排行榜,然后再根据 username 获取用户的hash信息,这个当时在实际运用中性能体验也蛮不错的。
- 分布式锁
这个主要利用 Redis 的
setnx
命令进行,setnx
:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0 ,这个特性在俞你奔远方的后台中有所运用,因为我们服务器是集群的,定时任务可能在两台机器上都会运行,所以在定时任务中首先 通过setnx
设置一个 lock,如果成功设置则执行,如果没有成功设置,则表明该定时任务已执行。 当然结合具体业务,我们可以给这个 lock 加一个过期时间,比如说30分钟执行一次的定时任务,那么这个过期时间设置为小于30分钟的一个时间 就可以,这个与定时任务的周期以及定时任务执行消耗时间相关。当然我们可以将这个特性运用于其他需要分布式锁的场景中,结合过期时间主要是防止死锁的出现。
- 延时操作
比如在订单生产后我们占用了库存,10分钟后去检验用户是够真正购买,如果没有购买将该单据设置无效,同时还原库存。 由于 Redis 自 2.8.0 之后版本提供 Keyspace Notifications 功能,允许客户订阅 Pub/Sub 频道,以便以某种方式接收影响 Redis 数据集的事件。 所以我们对于上面的需求就可以用以下解决方案,我们在订单生产时,设置一个 key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听 key 的实效,监听到 key 失效时将后续逻辑加上。 当然我们也可以利用 rabbitmq、activemq 等消息中间件的延迟队列服务实现该需求。
- 分页、模糊搜索
Redis 的 set 集合中提供了一个
zrangebylex
方法,语法如下:ZRANGEBYLEX key min max [LIMIT offset count]
通过
ZRANGEBYLEX zset - + LIMIT 0 10
可以进行分页数据查询,其中- +表示获取全部数据
zrangebylex key min max
这个就可以返回字典区间的数据,利用这个特性可以进行模糊查询功能,这个也是目前我在 Redis 中发现的唯一一个支持对存储内容进行模糊查询的特性。
- 点赞、好友等相互关系的存储
Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。 又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。
- 队列
由于 Redis 有 list push 和 list pop 这样的命令,所以能够很方便的执行队列操作。
MongoDB
优点:
- 更高的写负载,拥有更高的插入速度。
- 处理很大的规模的单表,当数据表太大的时候可以很容易的分割表。
- 高可用性,设置 M-S 不仅方便而且很快,还可以快速、安全及自动化的实现节点(数据中心)故障转移。
- 快速的查询,支持二维空间索引,比如管道,因此可以快速及精确的从指定位置获取数据。在启动后会将数据库中的数据以文件映射的方式加载到内存中。如果内存资源相当丰富的话,这将极大地提高数据库的查询速度。
- 非结构化数据的爆发增长,增加列在有些情况下可能锁定整个数据库,或者增加负载从而导致性能下降,由于弱数据结构模式,添加一个新字段不会对旧表格有任何影响,整个过程会非常快速。
缺点:
- 不支持事务。
- 占用空间过大 。
- 没有成熟的维护工具。
应用:
- 网站数据
Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
- 缓存
由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。
- 大尺寸、低价值的数据
使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
- 高伸缩性的场景
Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。
- 用于对象及JSON 数据的存储
Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。
对比
性能:总的来讲:Memcached 和 Redis 差不多,要高于 MongoDB。
便利性:
- Memcached 数据结构单一。
- Redis 丰富一些,数据操作方面,Redis 更好一些,较少的网络 IO 次数。
- MongoDB 支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富。
存储空间:
- Memcached 可以修改最大可用内存,采用 LRU 算法。
- Redis 在 2.0 版本后增加了自己的 VM 特性,突破物理内存的限制;可以对 key-value 设置过期时间。
- MongoDB 适合大数据量的存储,依赖操作系统 VM 做内存管理,吃内存也比较厉害,不要和别的服务在一起。
可用性:
- Memcached 本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的 hash 或者环状的算法,解决单点故障引起的抖动问题。
- Redis 依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,所以单点问题比较复杂;不支持自动 sharding,需要依赖程序设定一致 hash 机制。一种替代方案是,不用 redis 本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡。
- MongoDB 支持 master-slave,replicaset(内部采用 paxos 选举算法,自动故障恢复),auto sharding 机制,对客户端屏蔽了故障转移和切分机制。
可靠性:
- Memcached 不支持快照、AOF,通常用在做缓存,提升性能。
- Redis 支持快照、AOF,依赖快照进行持久化,aof 增强了可靠性的同时,对性能有所影响。
- MongoDB 从1.8版本开始采用 binlog 方式支持持久化的可靠性。
一致性:
- Memcached 在并发场景下,用 cas 保证一致性。
- Redis 事务支持比较弱,只能保证事务中的每个操作连续执行。
- MongoDB 不支持事务。
数据分析:MongoDB 内置了数据分析的功能(mapreduce),其他两者不支持。
应用场景:
- Memcached:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能。
- Redis:数据量较小的更新操作和运算上。
- MongoDB:主要解决海量数据的访问效率问题。