Mongo、Redis、Memcached对比及知识总结

存储原理(持久化)

  • Mongo
    Mongo的数据将会保存在底层文件系统,所以存储容量远大于redis和memcached。一个database中全部的collections以及索引信息会分散存储在多个数据文件中,即mongodb并无像SQL数据库那样,每一个表的数据、索引分别存储;数据分块的单位为extent(范围,区域),即一个data file中有多个extents组成,extent中能够保存collection数据或者indexes数据,一个extent只能保存同一个collection数据,不一样的collections数据分布在不一样的extents中,indexes数据也保存在各自的extents中;最终,一个collection有一个或者多个extents构成,最小size为8K,最大能够为2G,依次增大;它们分散在多个data files中。对于一个data file而言,可能包含多个collection的数据,即有多个不一样collections的extents、index extents混合构成。每一个extent包含多条documents(或者index entries),每一个extent的大小可能不相等,但一个extent不会跨越2个data files。

clipboard.png

  • Redis
    一、Redis的数据存储在内存中,同时能够经过两种存储机制,将数据持久化到磁盘。
    (1)Snapshot工做原理: 是将数据先存储在内存,而后当数据累计达到某些设定的伐值的时候,就会触发一次DUMP操做,将变化的数据一次性写入数据文件(RDB文件)
    (2)AOF 工做原理: 是将数据也是先存在内存,可是固定时候会使用调用fsync来完成对本次写操做的日志记录,这个日志揭露文件实际上是一个基于Redis网络交互协议的文本文件。AOF调用fsync也不是说所有都是无阻塞的,在某些系统上可能出现fsync阻塞进程的状况,对于这种状况能够经过配置修改,但默认状况不要修改。AOF最关键的配置就是关于调用fsync追加日志文件的频率,有两种预设频率,always每次记录进来都添加,everysecond 每秒添加一次。当redis重启时,将会读取AOF文件进行“重放”以恢复到redis关闭前的最后时刻。
    (3)两种存储原理比较:html

    a.性能
     Snapshot方式的性能是要明显高于AOF方式的,缘由有两点:
     采用2进制方式存储数据,数据文件比较小,加载快速。存储的时候是按照配置中的save策略来存储,每次都是聚合不少数据批量存储,写入的效率很好,而AOF则通常都是工做在实时存储或者准实时模式下。相对来讲存储的频率高,效率却偏低。
     
     b.数据安全
     AOF数据安全性高于Snapshot存储,缘由:
     Snapshot存储是基于累计批量的思想,也就是说在容许的状况下,累计的数据越多那么写入效率也就越高,但数据的累计是靠时间的积累完成的,那么若是在长时间数据不写入RDB,但Redis又遇到了崩溃,那么没有写入的数据就没法恢复了,可是AOF方式恰恰相反,根据AOF配置的存储频率的策略能够作到最少的数据丢失和较高的数据恢复能力。
  • Memcached
    一、Memcached不支持内存数据的持久化操做,因此的数据都以in-momory的造成存储。

数据类型:

  • Mongo
    一、字符串、整型、布尔型、双进度浮点型...具体参照:http://www.yiibai.com/mongodb...
  • Redis
    一、除了简单的key-value数据类型,同时还提供了list、hash、set、zset等数据结构的存储
  • Memcached
    一、Memcached使用key-value形式存储和访问数据

网络IO模型

  • Mongo
    一、多线程,同步 IO 模型。
    clipboard.png
    由主线程进行 accept 链接,而后针对每个链接建立一个线程进行处理,「thread per connection」这种模型:
    (1)不适合短链接服务,建立/删除线程的开销是巨大的,体如今建立线程时间和至少1MB 内存的使用。
    (2)伸缩性受到线程数的限制,200+线程数的调度对 OS 也是不小的负担。另外随着线程数的增长, 因为 mongo 自己业务的特性,对数据处理的并发度并不高,DB锁和全局的原子操做形成的 context-switch 也是急剧上升,性能反而降低,频繁的线程切换对于 cache 也不友好。
  • Redis
    一、Redis使用 单线程的IO复用模型 ,本身封装了一个简单的Ae_Event事件处理框架,主要实现了epoll、kqueue、kvport和select,对于单存只有IO操做来讲,单线程能够将速度优点发挥到最大,可是Redis也提供了一些简单的计算功能,好比排序、聚合等,对于这些操做,单线程模型不能发挥多核CPU的优点,会严重影响总体吞吐率,由于在CPU的计算的过程当中,整个IO调度是被阻塞的,所以 Redis不适合用于计算。
  • Memcached
    一、Memcached是 多线程、非阻塞IO复用 的网络模型,分为监听主线程和worker子线程,监听线程监听网络链接,接受请求后,将链接描述字pipe传递给worker线程进行读写IO,网络层使用libevent封装的事件库,多线程模型能够发挥CPU多核做用,可是引入了cache coherency(缓存一致性)和锁的问题,好比:Memcached最经常使用的stats命令,实际Memcached全部操做都要对这个全局变量加锁、进行技术工做等,带来了性能损耗。(缓存的一致性就是指缓存中的数据是否和目标存储中的数据是同样的,也就是说缓存中已经修改得数据是否已经保存到了物理存储中,物理存储中已经被修改得内容,是否与缓存的内容是同样的。这就是一致性的概念。)

内存管理机制

  • Redis
    一、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释放掉。

    clipboard.png

    二、在Redis中,并非全部的数组都一直存储在内存中的。这是和Memcached相比最大的一个区别。当物理内存用完的时候,Redis能够将一些好久没用到的value交换到磁盘(注:这里用到的是Redis的Virtual Memory技术,Redis2.4版本以后已经不提倡使用了)。Redis只会缓存全部key的信息,若是Redis发现内存的使用量超过了某个阈值,将触发swap操做。swap操做根据规则计算出哪些key对应的value须要swap到磁盘,而后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis能够保存超过其机器物理内存大小的数据。固然,机器自己的内存必需要可以保存全部的key,毕竟这部分数据是不会被swap到磁盘的。同时因为Redis将内存中的数据swap到磁盘的时候,提供服务的主线程和进行swap的子线程会共享这部份内存,全部若是须要更新swap的数据,Redis将阻塞这个操做,直到子线程完成swap以后才能够进行修改。当从Redis中读取数据的时候,若是读取的key的value不在内存中,那么Redis须要从swap文件中加载对应的数据,而后再返回给client,这里就存在一个I/O线程池的问题。在默认状况下,Redis会出现阻塞,即完成全部的swap文件加载后才会执行相应的操做。这种策略在client数量较小,进行批量操做的时候比较合适。可是若是Redis应用在一个大型的网站应用中,这显示是没法知足大并发的状况的。因此Redis容许咱们设置I/O线程池的大小,对须要从swap文件中加载相应数据的读取请求进行并发操做,减小阻塞的时间。redis

  • Memcached
    一、Memcached默认使用Slab Allocation机制来管理内存,它的主要思想是 按照预先规定的大小,将分配的内存分割成特定长度的块,以存储相应长度的key-value数据记录,以彻底解决内存碎片的问题。Slab Allocation机制只为存储外部数据而设计,也就是说全部的key-value数据都存储在slab allocation系统里面,可是Memcached的其余内存请求则是经过普通的malloc/free来申请,由于这些请求的数量和频率决定了它们不会对整个系统的性能形成影响。
    二、slab allocation机制的原理比较简单,以下图所示,它首先从操做系统申请一大块内存,并将其分割成各类尺寸的chunk(块),并把尺寸相同的chunk分红一组组slab class。其中,chunk就是用来存储key-value的最小单位。每一个slab class的大小,能够在Memcached启动的时候经过制定growth factor来控制。
    clipboard.png

    三、当Memcached接收到客户端发过来的数据时,会根据收到数据的大小选择一个最合适的slab class,而后经过查询Memcached保存着的该slab class内空闲chunk的列表,就能够找到一个用于存储数据的chunk。当一条数据记录过时或者丢弃时,该记录所占用的chunk就能够被回收,从新添加到空闲列表中。
    四、从以上过程当中能够看到,Memcached的内存管理效率高,而且不会形成内存碎片,可是它最大的不足是会形成空间浪费。由于每一个chunk都分配了特定长度的内存空间,因此变长数据没法利用这些空间。以下图所示,将100字节的数据缓存到128字节的chunk中,剩余的28个字节就被浪费掉了。
    clipboard.png算法

集群管理

  • Mongo
    一、Replica Set:中文翻译叫作副本集,就是集群当中包含了多份数据,保证主节点挂掉了,备节点能继续提供数据服务,提供的前提就是数据须要和主节点一致。以下图:
    clipboard.png
    二、Mongodb(M)表示主节点,Mongodb(S)表示备节点,Mongodb(A)表示仲裁节点。主备节点存储数据,仲裁节点不存储数据。客户端同时链接主节点与备节点,不链接仲裁节点。
    三、默认设置下,主节点提供全部增删查改服务,备节点不提供任何服务。可是能够经过设置使备节点提供查询服务,这样就能够减小主节点的压力,当客户端进行数据查询时,请求自动转到备节点上。这个设置叫作Read Preference Modes,同时Java客户端提供了简单的配置方式,能够没必要直接对数据库进行操做。
    四、仲裁节点是一种特殊的节点,它自己并不存储数据,主要的做用是决定哪个备节点在主节点挂掉以后提高为主节点,因此客户端不须要链接此节点。这里虽然只有一个备节点,可是仍然须要一个仲裁节点来提高备节点级别(由备用节点提高为主节点)。仲裁节点是必须的。详见:http://blog.csdn.net/luonanqi...
  • Redis
    一、相比Memcached只能采用客户端实现分布式存储,Redis更偏向在服务端构建分布式存储。新版本的Redis已经支持分布式存储功能。Redis Cluster是一个实现了分布式而且容许单点故障的Redis高级版本,它没有中心节点,具备线性可伸缩的功能。Redis Cluster的分布式存储架构,节点与节点之间经过二进制协议进行通信,节点与客户端之间经过ascii协议通信。在数据的放置策略上,Redis Cluster将整个key的数值域划分红16384(2^14)个哈希槽,每一个节点上能够存储一个或多个哈希槽,也就是说Redis Cluster支持的最大节点数是16384。
    二、为了保证单点故障下得数据可用性,Redis Cluster引入了Master节点和Slave节点。在Redis Cluster中,每一个Master节点都会对应2个用于冗余的Slave节点。这样在整个集群中,任意2个节点的宕机都不会致使数据的不可用。当Master节点下线后,集群会自动选择一个Slave节点成为新的Master节点。
  • Memcached
    一、Memcached是全内存的数据缓冲系统,Redis虽然支持数据的持久化,可是全内存才是其高性能的本质。做为基于内存的存储系统来讲,机器物理内存的大小就是系统可以容纳的最大数据量。若是数据超过了单台机器的物理内存大小,那么就须要构建集群来扩展存储能力。
    二、Memcached自己并不支持分布式,所以只能在客户端经过像一致性哈希这样的分布式算法来实现Memcached的分布式存储。

应用场景

  • Memcached及Redis
    一、相对memcached来讲,须要保证数据不丢失的话,选择Redis。
    二、固然,大部分状况来讲,选择Redis是一个更好的选择,由于它更强大、更受欢迎,而且比Memcached有更多的支持者。Memcached只是Redis功能中的一小部分。因此对于新项目来讲,选择Redis。
  • Mongo
    一、Mongo的使用和上面两个数据库是不冲突的,这篇文字只是作一个知识的总结。
    二、日志、消息记录;不须要事务,不需复杂join链接表;须要大容量存储;高吞吐量;数据不丢失;高可用;使用Mongo。

参考:

http://blog.csdn.net/sun49192...
https://www.zhihu.com/questio...
https://yq.aliyun.com/article...mongodb

相关文章
相关标签/搜索