MongoDB 3.0 新增特性一览
引言
在历经版本号修改(2.8 版本直接跳到 3.0 版本)和 11 个 rc 版本之后,MongoDB 3.0 于 2015 年 3 月 3 日正式发布。可以毫不夸张的说,该版本的新增特性标志着 MongoDB 这款典型的 NoSQL 数据库已经进入了一个全新的发展阶段。本文以下内容会逐个盘点 3.0 版本的新增特性。
插件式存储引擎 API
MongoDB 3.0 引入了插件式存储引擎 API,为第三方的存储引擎厂商加入 MongoDB 提供了方便,这一变化无疑参考了 MySQL 的设计理念。目前除了早期的 MMAP 存储引擎外,WiredTiger 和 RocksDB 均已完成了对 MongoDB 的支持,前者更是在被 MongoDB 公司收购后更是直接引入到了 MongoDB 3.0 版本中。插件式存储引擎 API 的引入为 MongoDB 丰富自己武器库以处理更多不同类型的业务提供了无限可能,内存存储引擎、事务存储引擎甚至 Hadoop 在未来都有可能接入进来。


WiredTiger 存储引擎
如果说插件式存储引擎 API 为 MongoDB 3.0 打造了一个武器库,那么 WiredTiger 绝对是武器库中第一枚也是最重要的一枚重磅炸弹。因为 MMAP 存储引擎自身的天然缺陷(耗费磁盘空间和内存空间且难以清理,库级别锁),MongoDB 为数据库运维人员带来了极大痛苦,甚至一部分人已经开始转向 TokuMX,尽管后者目前也不甚稳定。意识到这一问题的 MongoDB,做出了有钱任性的决定,直接收购存储引擎厂商 WiredTiger,将 WiredTiger 存储引擎集成进 3.0 版本(仅在 64 位版本中提供)。那么这款走到聚光灯下的存储引擎究竟具备哪些值得期待的特性呢?
1、文档级别并发控制
WiredTiger 通过 MVCC 实现文档级别的并发控制,即文档级别锁。这就允许多个客户端请求同时更新一个集合内存的多个文档,再也不需要在排队等待库级别的写锁。这在提升数据库读写性能的同时,大大提高了系统的并发处理能力。关于这一点的效果从监控工具 mongostat 就可以直接体现出来,旧版本的监控指标会有 locked db 这一项(该项指标过高是 mongo 使用人员的一大痛点啊),而新版的 mongostat 已经看不到了。

MongoDB 2.4.12 版本
$ home/mongodb/mongodb-linux-x86_64-2.4.12/bin/mongostat –port 55060
insert query update delete getmore command flushes mapped vsize res faults locked db idx miss % qr|qw ar|aw netIn netOut conn time
*0 *0 *0 *0 0 1|0 0 18g 18.3g 16.1g 0 ycsb:0.0% 0 0|0 0|0 62b 2k 1 13:04:01
*0 *0 *0 *0 0 1|0 0 18g 18.3g 16.1g 0 ycsb:0.0% 0 0|0 0|0 62b 2k 1 13:04:02
*0 *0 *0 *0 0 1|0 0 18g 18.3g 16.1g 0 ycsb:0.0% 0 0|0 0|0 62b 2k 1 13:04:03
MongoDB 3.0 rc8 版本
$ home/mongodb/mongodb-linux-x86_64-3.0.0-rc8/bin/mongostat –port 55050
insert query update delete getmore command % dirty % used flushes vsize res qr|qw ar|aw netIn netOut conn time
*0 *0 *0 *0 0 1|0 0.0 42.2 0 30.6G 30.4G 0|0 0|0 79b 16k 1 13:02:38
*0 *0 *0 *0 0 1|0 0.0 42.2 0 30.6G 30.4G 0|0 0|0 79b 16k 1 13:02:39
*0 *0 *0 *0 0 1|0 0.0 42.2 0 30.6G 30.4G 0|0 0|0 79b 16k 1 13:02:40
2、磁盘数据压缩
WiredTiger 支持对所有集合和索引进行 Block 压缩和前缀压缩(如果数据库启用了 journal,journal 文件一样会压缩),已支持的压缩选项包括:不压缩、Snappy 压缩和 Zlib 压缩。这为广大 Mongo 使用者们带来了又一福音,因为很多 Mongo 数据库都是因为 MMAP 存储引擎消耗了过多的磁盘空间而不得已进行扩容。其中 Snappy 压缩为数据库的默认压缩方式,用户可以根据业务需求选择适合的压缩方式。理论上来说,Snappy 压缩速度快,压缩率 OK,而 Zlib 压缩率高,CPU 消耗多且速度稍慢。当然,只要选择使用压缩,Mongo 肯定会占用更多的 CPU 使用率,但是考虑到 Mongo 本身并不是十分耗 CPU,所以启用压缩完全是值得的。



此外,WiredTiger 存储方式上也有很大改进。旧版本 Mongo 在数据库级别分配文件,数据库中的所有集合和索引都混合存储在数据库文件中,所以即使删掉了某个集合或者索引,占用的磁盘空间也很难及时自动回收。WiredTiger 在集合和索引级别分配文件,数据库中的所有集合和索引均存储在单独的文件中,集合或者索引删除后,对应的存储文件随即删除。当然,因为存储方式不同,低版本的数据库无法直接升级到 WiredTiger 存储引擎,只能通过导出导入数据的方式来实现。
MongoDB 2.4.12 版本
[mongodb@mongo-data-emergency-001.m6.momo.com mongodb_2_4_12]$ ll
drwxrwxr-x 3 mongodb mongodb 4096 2 月 25 19:03 local
-rwxrwxr-x 1 mongodb mongodb 6 2 月 25 19:04 mongod.lock
drwxrwxr-x 2 mongodb mongodb 4096 2 月 27 18:30 _tmp
drwxrwxr-x 3 mongodb mongodb 4096 2 月 27 18:39 ycsb
[mongodb@mongo-data-emergency-001.m6.momo.com mongodb_2_4_12]$ ll ycsb/
drwxrwxr-x 2 mongodb mongodb 4096 2 月 27 18:39 _tmp
-rw——- 1 mongodb mongodb 67108864 2 月 27 18:57 ycsb.0
-rw——- 1 mongodb mongodb 134217728 2 月 27 18:57 ycsb.1
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.10
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.11
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.12
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:39 ycsb.13
-rw——- 1 mongodb mongodb 268435456 2 月 27 18:57 ycsb.2
-rw——- 1 mongodb mongodb 536870912 2 月 27 18:57 ycsb.3
-rw——- 1 mongodb mongodb 1073741824 2 月 27 18:57 ycsb.4
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.5
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.6
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.7
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.8
-rw——- 1 mongodb mongodb 2146435072 2 月 27 18:57 ycsb.9
-rw——- 1 mongodb mongodb 16777216 2 月 27 18:40 ycsb.ns
Mongo 3.0 rc8 版本
[mongodb@mongo-data-emergency-001.m6.momo.com mongodb_3_0_0]$ ll
drwxrwxr-x 2 mongodb mongodb 4096 2 月 28 18:32 local
-rw-rw-r– 1 mongodb mongodb 36864 3 月 21 13:41 _mdb_catalog.wt
-rwxrwxr-x 1 mongodb mongodb 6 2 月 28 18:32 mongod.lock
-rw-rw-r– 1 mongodb mongodb 36864 3 月 21 13:42 sizeStorer.wt
-rw-rw-r– 1 mongodb mongodb 95 2 月 28 18:32 storage.bson
-rw-rw-r– 1 mongodb mongodb 49 2 月 28 18:32 WiredTiger
-rw-rw-r– 1 mongodb mongodb 433 2 月 28 18:32 WiredTiger.basecfg
-rw-rw-r– 1 mongodb mongodb 21 2 月 28 18:32 WiredTiger.lock
-rw-rw-r– 1 mongodb mongodb 921 3 月 21 13:41 WiredTiger.turtle
-rw-rw-r– 1 mongodb mongodb 53248 3 月 21 13:41 WiredTiger.wt
drwxrwxr-x 2 mongodb mongodb 4096 3 月 21 13:41 ycsb
[mongodb@mongo-data-emergency-001.m6.momo.com mongodb_3_0_0]$ ll ycsb/
-rw-rw-r– 1 mongodb mongodb 19314257920 2 月 28 19:16 collection-4–1318477584648278106.wt
-rw-rw-r– 1 mongodb mongodb 602112 3 月 21 13:40 collection-6–1318477584648278106.wt
-rw-rw-r– 1 mongodb mongodb 262598656 2 月 28 18:53 index-5–1318477584648278106.wt
-rw-rw-r– 1 mongodb mongodb 827392 3 月 21 13:40 index-7–1318477584648278106.wt
-rw-rw-r– 1 mongodb mongodb 1085440 3 月 21 13:41 index-8–1318477584648278106.wt
3、可配置内存使用上限
WiredTiger 支持内存使用容量配置,用户通过 storage.wiredTiger.engineConfig.cacheSizeGB 参数即可控制 MongoDB 所能使用的最大内存,该参数默认值为物理内存大小的一半。这也为广大 Mongo 使用者们带来了又一福音,MMAP 存储引擎消耗内存是出了名的,只要数据量够大,简直就是有多少用多少。
MMAPv1 存储引擎提升
MongoDB 3.0 出了引入 WiredTiger 外,对于原有的存储引擎 MMAP 也进行了一定的完善,该存储引擎依然是 3.0 版的默认存储引擎。遗憾的是改进后的 MMAP 存储引擎依旧在数据库级别分配文件,数据库中的所有集合和索引都混合存储在数据库文件中,所以磁盘空间无法及时自动回收的问题如故。
1、锁粒度由库级别锁提升为集合级别锁
这在一定程度上也能够提升数据库的并发处理能力。
2、文档空间分配方式改变
在 MMAP 存储引擎中,文档按照写入顺序排列存储。如果文档更新后长度变长且原有存储位置后面没有足够的空间放下增长部分的数据,那么文档就要移动到文件中的其他位置。这种因更新导致的文档位置移动会严重降低写性能,因为一旦文档发生移动,集合中的所有索引都要同步修改文档新的存储位置。
MMAP 存储引擎为了减少这种情况的发生提供了两种文档空间分配方式:基于 paddingFactor(填充因子)的自适应分配方式和基于 usePowerOf2Sizes 的预分配方式,其中前者为默认方式。第一种方式会基于每个集合中文档更新历史计算文档更新的平均增长长度,然后在新文档插入或旧文档移动时填充一部分空间,如当前集合 paddingFactor 的值为 1.5,那么一个大小为 200 字节的文档插入时就会自动在文档后填充 100 个字节的空间。第二种方式则不考虑更新历史,直接为文档分配 2 的 N 次方大小的存储空间,如一个大小同样为 200 字节的文档插入时直接分配 256 个字节的空间。
MongoDB 3.0 版本中的 MMAPv1 抛弃了基于 paddingFactor 的自适应分配方式,因为这种方式看起来很智能,但是因为一个集合中的文档的大小不一,所以经过填充后的空间大小也不一样。如果集合上的更新操作很多,那么因为记录移动后导致的空闲空间会因为大小不一而难以重用。目前基于 usePowerOf2Sizes 的预分配方式成为默认的文档空间分配方式,这种分配方式因为分配和回收的空间大小都是 2 的 N 次方(当大小超过 2MB 时则变为 2MB 的倍数增长),因此更容易维护和利用。如果某个集合上只有 insert 或者 in-place update,那么用户可以通过为该集合设置 noPadding 标志位,关闭空间预分配。
复制集改进
1、复制集成员增长
MongoDB 3.0 的复制集成员的最大个数由之前的 12 个增长为 50 个,但能够投票的最大成员个数依然为 7 个,而相应的 getLastError 中的 w: “majority” 项也仅代表投票节点的大多数。
2、Primary 节点 StepDown 处理方式变化
在复制集中通过 replSetStepDown 命令可以使得当前的 Primary 节点退位,重新选举新的 Primay 节点。MongoDB 3.0 在 StepDown 的处理方式上做了如下修改:1)在 Primary 退位之前,会首先中断某些耗时较长的用户操作如创建索引、写操作、Mapreduce 任务等;2)为了防止数据回滚,Primary 节点在退位之前会等待一个可被选举的 Secondary 节点同步到最新数据,而旧版本中 Primary 节点只要有 Secondary 节点的数据同步到 10 秒以内就退位;3)同时 replSetStepDown 命令新增了一个 secondaryCatchUpPeriodSecs 参数,用户可以指定 Primary 节点等待有 Secondary 节点的数据同步到该参数指定的秒数内就退位。
分片集群改进
1. 新增工具函数 sh.removeTagRange()
旧版本中只有 sh.addTagRange(),如果要删除 tagRange 只能手工到 config.tags 集合中删除。
2. 提供更可预测的 Read Preference 处理
新版本中 mongos 实例在执行读操作时不再将连接固定在复制集成员上,而是对每个读操作都会重新评估 Read Preference。这样当 Read Preference 修改时,其行为更容易预测。
3. 为 chunk 迁移提供 writeConcern 设置
新版本针对均衡器为 moveChunk 和 cleanupOrphaned 这两个涉及到 chunk 迁移的命令提供了 writeConcern 参数。
4. 增加均衡器状态显示
新版本中通过 sh.status() 可以看到均衡器的状态信息。
其他改进
1、优化 explan 函数
新版本 explain 函数可以支持 count,find,group,aggregate,update,remove 等操作的查询计划显示,结果更全面更精细。
2、重写 mongodb 工具
新版本所有 mongodb 自带工具均使用 Go 语言重写,特别是在 mongodump 和 mongorestore 添加了并行机制,这样可以大大加快数据的导出和导入。
3、日志输出控制
新版本中将日志分为不同的模块,其中包括 ACCESS、COMMAND、CONTROL、GEO、INDEX、NETWORK、QUERY、REPL、SHARDING、STORAGE、JOURNAL 和 WRITE 等。用户可以动态调整每个模块的日志级别,这无疑更有利于系统问题诊断。
4、 索引构建优化
后台索引建立过程中,不能进行删库删表删索引操作,且后台索引建立过程不会因此自动中断。另外,使用 createIndexes 命令可以同时建立多个索引,并且只扫描一遍数据,提升了建索引的效率。
总结
以上仅列出了 MongoDB 3.0 的一些主要特性和修改,如果希望了解更多可以查看 MongoDB 3.0 的 Release-Notes。总体来看,MongoDB 3.0 提供了较多令人惊喜的新特性,也使人们更加看好其未来的发展。
参考资料链接
MongoDB 3.0 官方 Release-Notes:http://docs.mongodb.org/manual/release-notes/3.0/
北京 Mongo 用户组第二次线下活动 PPT:http://www.mongoing.com/archives/543
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&id=4865696&uid=15795819
http://blog.sina.com.cn/s/blog_48c95a190102vedr.html
#sohu-dba#




