MongoDB作为NoSQL数据库中功能最多也是最为接近传统关系数据库的的一种,有着较为广泛的应用,特别是基于文档的无Schema数据存储方式以及基于Replica Set的复制和故障转移机制,相比传统的关系数据库有着明显的优势。然而在之前的使用过程中发现,由于MongoDB采用mmap的方式将数据的缓存工作交给操作系统处理,导致缓存的效率较低,并且当数据量远大于内存后性能下降非常明显,经常出现慢查询导致崩溃的情况。
而在MongoDB 3.0中其增加类似MySQL存储引擎的概念,除了默认的mmapv1,增加了wiredTiger,其自身能够对数据进行缓存,类似InnoDB,而根据官方的测试说其性能要明显好于LevelDb和InnoDB,具体可以参考http://www.wiredtiger.com/。
根据官方提供的升级文档,只有2.6以上的版本可以直接升级到3.0,否则需要先升级到2.6再进行升级。如果只是升级mongod的版本,则升级过程非常简单,只需要下载最新版本的二进制包,暂时停止mongod,再替换掉老的二进制文件后重新启动即可,数据文件格式是可以向下兼容的,然后升级后不能再进行降级,这一点需要特别注意,条件允许的情况下做好数据的备份也是很有必要的。另外如果使用了Replica Set的复制可以先升级一个SECONDARY,然后再用相同的方法升级其他的SECONDARY,升级PRIMARY时则将其强制将为SECONDARY再进行升级操作,如此可以做到无间断的升级,MongoDB的Replica Set复制允许不同的实例之间存在版本的差异。
切换PRIMARY时,连接到当前的PRIMARY,并在mongo shell中执行一下操作即可强制进行PRIMARY的故障转移
rs.stepDown();
执行后当前的PRIMARY会被切换为SECONDARY,输出如下
upgrade:PRIMARY> rs.stepDown(); 2015-10-14T21:45:30.800+0800 I NETWORK DBClientCursor::init call() failed 2015-10-14T21:45:30.808+0800 E QUERY Error: error doing query: failed at DBQuery._exec (src/mongo/shell/query.js:83:36) at DBQuery.hasNext (src/mongo/shell/query.js:240:10) at DBCollection.findOne (src/mongo/shell/collection.js:187:19) at DB.runCommand (src/mongo/shell/db.js:58:41) at DB.adminCommand (src/mongo/shell/db.js:66:41) at Function.rs.stepDown (src/mongo/shell/utils.js:1006:15) at (shell):1:4 at src/mongo/shell/query.js:83 2015-10-14T21:45:30.810+0800 I NETWORK trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed 2015-10-14T21:45:30.811+0800 I NETWORK reconnect 127.0.0.1:27017 (127.0.0.1) ok upgrade:SECONDARY>
然而只是更新mongod的版本带来的提升是比较有限的,升级的主要目的还是将数据该用新的wiredTiger引擎进行存储,更换存储引擎的方法可以类似MySQL中使用的数据格式升级的方法,即dump出和存储引擎无关的原始数据后更换存储引擎后再进行数据的导入即可完成数据格式的升级。
mongodump -o backup #修改配置后 mongorestore backup
然而使用这种升级的方法需要在操作的过程中中断服务,适用于小数据量同时没有使用Replica Set复制的情况。而如果使用了Replica Set复制就可以类似使用上面提到的升级mongod版本的方法进行。首先停止一个SECONDARY的mongod,修改数据文件的目录和使用的存储引擎。
storage: journal: enabled: true # dbPath: "/opt/mongo/3.0/data1-mmapv1" dbPath: "/opt/mongo/3.0/data1-wiredTiger" directoryPerDB: true # engine: "mmapv1" engine: "wiredTiger" wiredTiger: engineConfig: cacheSizeGB: 1 directoryForIndexes: true
重新启动后即开始自动恢复数据,恢复的数据将使用新的存储引擎,依次进行处理,处理到PRIMARY节点的时候使用上面类似的方法强制故障转移后进行处理即可。
在使用MongoDB较老的版本时发现如果oplog已经不完整,则增加新的节点的恢复过程会失败,即新的节点数据为空,而在3.0从2.6版本恢复的过程中没有遇到这一问题,官方的文档说恢复的过程是新节点会从其他的节点查询数据进行恢复,似乎是不再依赖于完整的oplog,感觉也是一个非常大的改进。
MongoDB能够进行的配置比较有限,新版本开始使用yaml文件作为配置文件,不过依然可以兼容以前类似ini方式的配置文件,一个简单的配置文件如下
systemLog: destination: file path: "/opt/mongo/3.0/log/mongod.1.log" logAppend: true storage: journal: enabled: true dbPath: "/opt/mongo/3.0/data1" directoryPerDB: true engine: "wiredTiger" wiredTiger: engineConfig: cacheSizeGB: 1 directoryForIndexes: true processManagement: fork: true net: bindIp: 127.0.0.1 port: 27017 setParameter: enableLocalhostAuthBypass: false replication: replSetName: "upgrade" oplogSizeMB: 1
之前在使用上也遇到一个问题——在Replica Set模式下,所有的查询都会走PRIMARY,而SECONDARY几乎完全没有作用,根据官方文档的说法为了保证数据的强一致性,在没有特殊声明的情况下客户端驱动会默认从PRIMARY进行查询,可以在客户端中做相应的设定使得驱动支持将一些查询分配到SECONDARY。如PHP中的操作方式如下
<?php $m = new MongoClient(); // Prefer the nearest server in the "east" data center also used for reporting, // but fall back to a server in the "west" data center $m->setReadPreference(MongoClient::RP_NEAREST, array( array('dc' => 'east', 'use' => 'reporting'), array('dc' => 'west'), )); ?>
RP_NEAREST文档中的解释是优先选用延迟最低的节点,然后在优先选用拥有对应tag值的节点。