周二有同学问,MONGODB怎么备份,怎么数据迁移,正好最近要做一个项目的数据迁移,其中就有MONGODB ,正好以一个项目的观念来看看MongoDb的数据迁移和备份的观点,如果有遗漏或三观不正,还是请大家来指正。
做这个事情,其实要先有一个测试环节,或者生产环境,这里就以两个单机的MOGNODB4.0 来进行操作。本身MONGODB 是支持两种数据的迁出和导入的方式,当然后面也会有两个复制集合之间的数据迁移的东西。
一般小型系统使用mongodump 和 mongorestore 来进行系统的备份和恢复mongodump可以用来转储整个数据库、集合或查询结果。mongodump可以通过转储oplog来生成一致的数据快照。mongorestore实用程序将数据恢复到新的或现有的数据库。mongorestore将从mongodump生成的BSON数据库转储中导入内容,并重播oplog。
mongodump只捕获数据库中的文档。产生的备份是空间有效的,但是mongorestore或mongod必须在恢复数据后重建索引。
但实际上,很多线上的MONGODB 系统可能并不是这样备份和恢复的。
但我们还是先看看相关的命令,对于小型的系统来说还是使用这样的方式来备份。
备份(J 为操作使用的线程, --gzip 是压缩)
mongodump --host=192.168.198.180 --port=27027 --username=admin --password=1234.com --authenticationDatabase=admin --gzip --db test -v -j 8 -o /mongodata/backup
数据的恢复
mongorestore --host=192.168.198.181 --port=27027 --username=admin --password=1234.com --authenticationDatabase=admin --db test -v --drop -j 8 --gzip --dir='/mongodata/backup/test'
对于单机来说上面的备份和恢复的方式基本上就满足了。当然可以写一个脚本,然后在rsync 到对应的备份存储的地方就可以。
但实际上很多MONGODB 的使用的方式都是复制集,那具体的复制replica set 是怎么备份的。
mongodump --uri="mongodb://backup:1234.com@10.5.1.114:27027,10.5.1.115:27027,10.5.1.116:27027/DB_AAP_LOG?replicaSet=repl&readPreference=secondary" --gzip -v -j 8 -o /wu
上面的命令就是从MONGODB3.46引入了 uri的方式连接MONGODB ,通过这样的方式来针对复制集合来进行备份 其中 -j 的方式对数量较多的数据进行备份。由于和--db 命令有冲突,直接可以在备份的指定的认证数据库就是要备份的数据块即可。(如有问题请指出)
实际上这里有一个点,就是MONGODB 是不是也需要类似传统数据库的锁,来将备份的数据的一致性进行一个限制,实际上这里是有选择的如果你选择了 mongodb 备份的时候增加了 --oplog 则会从备份开始添加相关的oplog日志,在恢复的时候可以使用,这里我个人认为就类型与 mysqldump 里面的 --single-transaction 有类似的功效。但需要的是,要对数据库进行FULL备份的时候才能应用,而不能对数据库中个别的库进行备份使用,这是理所当然的数据恢复后,是否需要对索引进行一个确认
下面的脚本可以在MONGODB 中直接运行,并获取当前数据库的索引信息
var collectionList = db.getCollectionNames();
for(var index in collectionList){
var collection = collectionList[index];
var cur = db.getCollection(collection).getIndexes();
if(cur.length == 1){
continue;
}
for(var index1 in cur){
var next = cur[index1];
if(next["key"]["_id"] == '1'){
continue;
}
print(
"try{ db.getCollection(\""+collection+"\").ensureIndex("+JSON.stringify(next.key)+",{background:1, unique:" + (next.unique || false) + "" + (next.expireAfterSeconds > 0 ? ", expireAfterSeconds :" + next.expireAfterSeconds : "") + " })}catch(e){print(e)}")}}
另外还有一个问题,就是如果我不备份整个MONGODB 我只备份一个库,然后想增量怎么办,可能就需要你的collection有相关的时间字段,然后export import 根据时间来进行,可能操作会稍微有点复杂。
例如下面的数据中,我们只想根据date 界限将一些数据导出
mongoexport -uXXX -pXXXXX --host 192.168.198.180:27027 -d test -c testData -q '{ date: { $lte: { "$date": "2020-03-30T02:23:25Z" } } }' --out /mongodata/backup/testData.json
这样我们就导出了你需要的数据
实际上如果用备份的方式,数据是可以压缩的比较小,但灵活性就相对差一些,导入导出数据的特点就是灵活,但占用的时间和空间会大。
mongoimport -uXXX -pXXXXX --host 192.168.198.181:27027 -d test -c testData --type json --file='/mongodata/backup/testData.json'
我们用上面的命令就将对应的数据导入
这里估计很多同学都会有疑问,mongodump mongorestore 和 mongoimport mongexport 比较后者灵活性在哪里,
举一个例子,当数据从一个表,要进入另一个表,并且有些字段还有取舍,同时由于数据可能有重复性,也就是_id 可能有重复的可能,这时你能选择的大概率是 mongoimport mongoexport , 通过下图的选项你可以让那些重复可能有冲突的数据“安安静静”的听你的指挥,至少你可以有选择,如果你使用dump resotre 那就........
在回到备份,如果你的数据库比较大,通过这样的方法来进行备份,那就.... 比较慢,是不是有更好的方式来对数据库进行备份,由于MONGODB 本身不具有强事务性,所以在MONGODB 备份中会经常用到这样一个命令,从MONGODB 3.2开始,就支持卷备份了。
就是下面这个命令了,在db.fsyncLock() 将你的MONGODB 的写锁住,然后就可以开始拷贝你的文件了,将你的文件都拷贝走,当然你可以LVM 等方式,具体的按你心愿,
在拷贝完毕后,在直接,键入db.fsyncUnlock() 解锁,数据就可以继续写入了。
实际上大部分的MONOGDB的数据库的(大容量)的备份都是这样的方式,尤其集群的方式中将从库锁定,然后拷贝从库的数据到备份位置,然后解开锁,但需要注意的是,你在操作的过程中的时间,和不要忘记你的数据库在被锁定,以及报警等方方面面的问题,你都需要去处理。
实际上对于MONGODB 的备份还有一种想法,就是直接在复制集的基础上,建立一个备份节点,我知道这样的想法可能做传统数据库的DB们不是很认同,如果人家的数据要回滚怎么办,如果数据要存档怎么办。当然也可以有延迟库(使用过MYSQL的小伙伴应该对这个概念不会陌生)
说到这里还是一个我的口头禅,任何事情都要看你的业务逻辑,如果你的MONGODB 仅仅是一个流水账,和一些日志的话,是否对这些东西必须要进行备份,另外备份的意义在哪里,例如如果你的数据库是 cassandra 那上百个节点的时候,怎么备份呢???? 所以不同的数据库可能会颠覆你长久以来的一些对数据库的操作的方法和态度,这世界变化快,follow it . (如果在生产时间备份,强烈建议全部在复制集合的从库上进行备份)
本文参加MongoDB中文社区征文活动,链接:https://mongoing.com/mongodb-blog-contest-2020-may