背景
关于“如何选择MongoDB存储引擎”的问题,已经被我的客户问过很多次,这篇文章也算是为客户写的吧。这里我们主要对比MonogoDB中MMAP和WiredTiger引擎间的区别,通过对比分析,期望能让您可以根据自己的需求为业务选择正确的引擎。
官方社区版MongoDB当前主要使用MMAPV1和WiredTiger引擎。当然我们也可以在企业版里使用内存引擎或percona版本(PSMDB)中使用rockDB引擎。MongoDB早期版本默认只有MMAPV1引擎,虽然到现在依然支持该引擎,但是需要注意的是按照MongoDB官方计划4.2版本将不再支持。对于那些当前可能已经不使用MMAPV1引擎,但曾经使用过MongoDB1.8版本的人来说可能会忽略一点,即MongoDB自从收购WiredTiger Inc(见 https://www.mongodb.com/press/wired-tiger)后,从3.2版本开始将WiredTiger设为默认引擎。WiredTiger引擎引入了多文档事务,同时也支持文档压缩和行级锁等特性。文末我将会用表格详细的对WiredTiger和MMAPV1引擎关键特性进行比较。
一、存储引擎概述
MMAPV1: MongoDB的原始存储引擎,在第一个版本中引入,从4.0版本开始被弃用。
WiredTiger: 在3.0版本中引入插件式引擎,从3.2版本开始变成了默认的存储引擎。
二、数据压缩
MMAPV1:
因为是基于内存映射文件,所以MMAPV1不支持压缩。如果所有数据都能放入内存那么它将变的非常高效。MMAPV1善于处理大量插入、删除及更新的工作场景。
WiredTiger:
支持snappy和zlib两种压缩模式。因此与MMAP相比,使用WiredTiger的MongoDB占用的磁盘空间要小很多。并且WiredTiger引擎本身有自己的写缓存(可配置)同时也能使用文件系统缓存。
Snappy:默认压缩策略,兼顾高效计算机合理的压缩。
详见,http://source.wiredtiger.com/mongodb-3.4/compression.html
Zlib: 高压缩比但是同时对cpu消耗也比较大。
详见,http://source.wiredtiger.com/mongodb-3.4/compression.html
三、数据目录
下面我们来看看相同副本集集群架构和同等数据的情况下文件系统布局情况
MMAPV1:

WiredTiger:

四、Journal日志
MMAPV1:
对于该引擎Journal可确保写入的”原子”性,即当某些修改在提交到数据文件之前MongoDB发生了崩溃,此时MongoDB可以使用journal日志在下次启动的时候应用对应修改操作到数据文件以保持数据一致性。
WiredTiger:
对于该引擎journal日志可以确保两个检查点之间所有数据修改的持久化。因此任何数据库的崩溃只需要最后一次检查点后的journal日志即可。大多数情况下对于引擎来说journal日志是不必要的,只有你想确保能恢复到崩溃之前最后一次成功的时候才需要使用journal日志。否则,MongoDB通常可以从最后一个有效checkpoint进行恢复,默认情况下MongoDB每分钟做一次checkpoint。
五、Journal目录
如下是不同引擎下journal的目录结构情况:
MMAPV1:

WiredTiger:

六、锁和并发控制
MMAPV1:
直到2.6版本MMAPV1都是采用读-写 [1] 锁进行并发控制,即允许并发读访问一个数据库,但是对于相同库的单个写操作之间只能是排他性的【库级别锁】。这就意味着当有一个读锁存在的时候,任意其他读操作也能共用该读锁。而当一个单个写操作持有写锁的时候,其他任何读或写操作都不能共用该写锁,故只能等待。
从3.0版本开始,MMAPv1存储引擎采用集合级别锁,这也是对早期版本的改进,早期版本中,库锁是最细粒度的锁。
WiredTiger:
支持文档级别锁,对于大多数读写操作,WiredTiger使用乐观并发控制。即WiredTiger只在全局、数据库和集合级别使用意向锁。
下面通过删除testData集合{x:1}的例子来说明不同引擎下获取集合级别“锁”的差别
MMAPV1:

根据MongoDB官方文档关于锁类型的解释大写W表示排他写锁(RepresentsExclusive (X) lock)
WiredTiger:

根据MongoDB官方文档关于锁类型的解释小写w表示意向排他锁(Represents IntentExclusive (IX) lock)
七、内存使用
MMAPV1:
该引擎下MongoDB将会使用机器所有的空闲内存作为自己的缓存。系统资源监控会显示MongoDB使用了大量的内存,但是这样的使用是动态的。假如有一个其他的进程突然想申请机器一半的内存,此时MonoDB将会让出自己的缓存内存给该进程使用。
从技术层面讲,MMAPV1引擎下的MongoDB内存由操作系统的虚拟内存子系统来管理。这就意味着MongoDB将使用尽可能多的空闲内存,并根据需要交换到磁盘。故给MongoDB足以覆盖所有热数据的内存容量将会使得MongoDB获得最佳的性能。
WiredTiger:
该引擎会同时使用引擎内部缓存和操作系统缓存资源。对于文件系统缓存,MongoDB将会自动使用WiredTiger缓存外及其他进程不使用的所有空闲内存。
从3.4版本开始WiredTiger引擎将默认使用如下两者中最大的那个缓存大小:
50% of (RAM – 1 GB)
256 MB
八、MMAPV1及 WiredTiger快速对比
关键特性MMAPV1引擎wiredTiger引擎
默认引擎引入 3.0版本及其之前作为MongoDB默认引擎,4.0 及其以后版本废弃3.0版本引入,3.2版本起作为默认引擎
数据压缩不支持默认采用 snappy 压缩模式同时支持zlib 压缩模式
Journal日志写操作首先在内存进行修改并将对应操作写入磁盘journal文件。如果修改在数据同步至磁盘之前MongoDB崩溃,重启之后MongoDB可以利用journal日志重新应用对应的写操作到数据文件从而保证数据一致性journal日志保存两个检查点之间的所有修改,如果MongoDB在下一个检查点之前崩溃,引擎将会使用journal重放最后一个检查点以来的所有数据修改操作
锁和并发控制Till 2.6, MongoDB uses a readers-writer [1] lock that allows concurrent reads access to a database but gives exclusive access to a single write operation. From 3.0, uses collection level lockIt supports document level locking.
事务单个文档操作具备原子性MongoDB4.0版本支持多文档事务
CPU与性能增加CPU核数对性能的提升有限多核系统中提升CPU核数可很大程度提升性能
数据加密不支持官方企业版和percona的3.6.8(PSMDB) BETA 版本支持
内存使用自动使用机器所有空闲内存作为自己的缓存同时使用引擎内部缓存及文件系统缓存
修改善于处理具有大量插入、读取和就地更新的工作场景不支持原地更新故会导致整个文档的重写
调优可调优的点极少允许通过不同的参数对引擎进行调优,比如: 内部缓存大小(cache size),读写并发控制(read / write tickets), 检查点触发时间间隔(checkpoint interval)等
九、结论
本文所述内容仅包含了MMAPV1与WiredTiger关键特性的对比
网友评论