mongodb复制集备份

一、论备份的重要性

不废话,自己去查网易的炉石传说故事,携程事故,过!

二、Mongodb备份策略介绍

2.1 使用Atlas备份

MongoDB 推出了Atlas,一个新型DaaS解决方案,它在云上运行MongoDB非常简便、活力且节约成本。无论运行的是一个单机副本集还是一个负载百兆字节的分片集群,Atlas作为一个服务于MongoDB的数据库,都可帮助其轻松运行,并未使用此方式所以在这里不做介绍。如有需求请跳转到Mongodb Atlas

2.2 MongoDB Cloud Manager 和Ops Manager

收费的,自己去学吧Mongodb Cloud Manager
Ops Manager

2.3 备份文件系统快照

此方法支持按照时间点的快照备份,你可以用这些快照实现mongodb系统的备份。文件系统快照是一个操作系统卷管理的特点并不是mongodb的专用的。使用文件系统快照,操作系统会使用卷的快照作为一个数据备份。快照的技术依赖于基础存储系统,例如linux的LVM就可以创建快照,aws的EBS也可以。运行的mongog进程必须开启journal,如果未开启,生成的快照则可能无效。查看更多信息请移步Back Up and Restore with Filesystem SnapshotsBack Up a Sharded Cluster with File System Snapshots

2.4 使用cp或者rsync

这个方式比较鸡肋,如果你的备份不支持快照,你可以直接copy或者rsync到远端或者类似的工具,当你拷贝的时候,必须要停止写操作,这就很蛋疼了,需要停停服务了,不能因为备份停止mongod进程吧,如果不停,备份的结果可能无效,而且此方式无法实现按照时间点的复制集和分片恢复,那就有mongodump诞生了

2.5使用mongodump备份

mongodump从Mongodb数据库中读取数据库并创建bson我的二进制文件,恢复数据使用mongorestore,这两个工具都是很简单并且高效的,但是对于一个很大的备份系统不是很合适。
这里要说下–oplog参数,–oplog可以实现按照时间点(point-in-time)的快照方式,针对复制集合master-slave方式较好,不建议stonalone的情况使用此办法。
看英文说明好牛B的样子,point-in-time快照哦,我第一次看到这句话的时候的理解是它可以让数据库回到这段时间中的任意一个时间点的状态,美了好一阵。但实际上并不是。它的实际作用是在导出的同时生成一个oplog.bson文件,存放在你开始进行dump到dump结束之间所有的oplog。这个东西具体有什么用先卖个关子。用图形来说明下oplog.bson的覆盖范围:

为了后面的讲解不至于把人说晕,进一步说明之前先解释一下什么是oplog及其相关概念。官方提供的文档其实已经很全面地做了解释,点击查看中文文档英文文档

简单地说,在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过–oplogSizeMB参数修改),位于local库的db.oplog.rs,有兴趣可以看看里面到底有些什么内容。其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。当空间用完时新记录自动覆盖最老的记录。所以从时间轴上看,oplog的覆盖范围大概是这样的:
其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。想要查看当前的oplog时间窗口预计值,可以使用以下命令:

  1. test:PRIMARY> rs.printReplicationInfo()
  2. configured oplog size: 1561.5615234375MB <--集合大小
  3. log length start to end: 423849secs (117.74hrs) <--预计窗口覆盖时间
  4. oplog first event time: Wed Sep 09 2015 17:39:50 GMT+0800 (CST)
  5. oplog last event time: Mon Sep 14 2015 15:23:59 GMT+0800 (CST)
  6. now: Mon Sep 14 2015 16:37:30 GMT+0800 (CST)
  • 幂等性(idempotent)。
    即对一个数据集合,使用oplog中记录的操作重放时,无论被重放多少次,其结果会是一样的。举例来说,如果oplog中记录的是一个插入操作,并不会因为你重放了两次,数据库中就得到两条相同的记录。这是一个很重要的特性,也是后面这些操作的基础。
      回到主题上来,看看oplog.bson到底有什么作用。首先要明白的一个问题是数据之间互相有依赖性,比如集合A中存放了订单,集合B中存放了订单的所有明细,那么只有一个订单有完整的明细时才是正确的状态。假设在任意一个时间点,A和B集合的数据都是完整对应并且有意义的(对非关系型数据库要做到这点并不容易,且对于MongoDB来说这样的数据结构并非合理。但此处我们假设这个条件成立),那么如果A处于时间点x,而B处于x之后的一个时间点y时,可以想象A和B中的数据极有可能不对应而失去意义。
      再回来看mongodump的操作。mongodump的进行过程中并不会把数据库锁死以保证整个库冻结在一个固定的时间点,这在业务上常常是不允许的。所以就有了dump的最终结果中A集合是10点整的状态,而B集合则是10点零1分的状态这种情况。这样的备份即使恢复回去,可以想象得到的结果恐怕意义有限。那么上面这个oplog.bson的意义就在这里体现出来了。如果在dump数据的基础上,再重做一遍oplog中记录的所有操作,这时的数据就可以代表dump结束时那个时间点(point-in-time)的数据库状态。
      这个结论成立的重要条件就是幂等性:已存在的数据,重做oplog不会重复;不存在的数据重做oplog就可以进入数据库。所以当做完截止到某个时间点的oplog时,数据库就恢复到了截止那个时间点的状态。
  • 恢复任意时间点数据
      聪明如你可能已经想到,既然dump出的数据配合oplog就可以把数据库恢复到某个状态,那是不是拥有一份从某个时间点开始备份的dump数据,再加上从dump开始之后的oplog,如果oplog足够长,是不是就可以把数据库恢复到其后的任意状态了?是的!事实上replica set正是依赖oplog的重放机制在工作。当secondary第一次加入replica set时做的initial sync就相当于是在做mongodump,此后只需要不断地同步和重放oplog.rs中的数据,就达到了secondary与primary同步的目的。
      既然oplog一直都在oplog.rs中存在,我们为什么还需要在mongodump时指定–oplog呢?需要的时候从oplog.rs中拿不就完了吗?答案是肯定的,你确实可以只dump数据,不需要oplog。在需要的时候可以再从oplog.rs中取。但前提是oplog时间窗口(忘了时间窗口概念的请往前翻)必须能够覆盖dump的开始时间。
      明白了这个道理,理论上只要我们的mongodump做得足够频繁,是可以保证数据库能够恢复到过去的任意一个时间点的。MMS(现在叫Cloud Manager)的付费备份也正是在利用这个原理工作。假设oplog时间窗口有24小时,那么理论上只要我在每24小时内完成一次dump,即可保证dump之后的24小时的point-in-time数据恢复。在oplog时间窗口快要滑出24小时的时候,只要及时完成下一次dump,就又可以有24小时的安全期。

三、开始备份

3.1 mongodump参数介绍

  1. # ./mongodump --help
  2. options:
  3. --help 显示帮助信息
  4. -v [ --verbose ] 打印出更多信息,如时间等等 -vvvvv
  5. --version 打印版本信息
  6. -h [ --host ] arg 指定连接的mongodb主机,复制集时设置为<set name>/s1,s2
  7. --port arg 指定mongodb端口号,也可以这么指定--host hostname:port
  8. --ipv6 启用支持IPv6 support
  9. -u [ --username ] arg 用户名
  10. -p [ --password ] arg 密码
  11. --authenticationDatabase arg user source (defaults to dbname)
  12. --authenticationMechanism arg (=MONGODB-CR)
  13. authentication mechanism
  14. --dbpath arg 直接访问mongod的数据库文件,而不是连接到mongodb服务器。需要锁定数据目录,如果mongod当前在访问相同路径将不能使用。也就是说,mongod运行的情况下不能使用--dbpathmongod未运行的情况下可以直接指定--dbpath
  15. --directoryperdb 每个db一个单独的目录,需要指定dbpath
  16. --journal 启用journaling,需要指定dbpath
  17. -d [ --db ] arg 指定数据库
  18. -c [ --collection ] arg 指定集合
  19. -o [ --out ] arg (=dump) 指定输出目录,"-"表示标准输出
  20. -q [ --query ] arg json查询
  21. --oplog 使用oplog来生产时间点快照
  22. --repair 尝试恢复崩溃的数据库
  23. --forceTableScan 强制表扫描,不使用$snapshot

3.1 mongoresore参数介绍

  1. # ./mongorestore --help //相同部分参数意义参加上面的mongodump
  2. -v [ --verbose ]
  3. --version
  4. -h [ --host ] arg
  5. --port arg
  6. --ipv6
  7. -u [ --username ] arg
  8. -p [ --password ] arg
  9. --authenticationDatabase arg
  10. --authenticationMechanism arg (=MONGODB-CR)
  11. --dbpath arg
  12. --directoryperdb
  13. --journal
  14. -d [ --db ] arg
  15. -c [ --collection ] arg
  16. --objcheck 在插入前验证对象,默认启用
  17. --noobjcheck 不在插入前验证对象
  18. --filter arg 插入前过滤
  19. --drop 在插入前删除所有文档
  20. --oplogReplay 在恢复时应用oplog
  21. --oplogLimit arg include oplog entries before the
  22. provided Timestamp (seconds[:ordinal])
  23. during the oplog replay; the ordinal
  24. value is optional
  25. --keepIndexVersion don't upgrade indexes to newest version
  26. --noOptionsRestore don't restore collection options
  27. --noIndexRestore don't restore indexes
  28. --w arg (=0) minimum number of replicas per write

3.3备份开始

在这里使用复制集的方式来实验,备份的目标是所有库,当然当你备份某个库或者复制集的时候是不能指定oplog参数的,备份的同时会在默认当前目录创建dump目录存放备份的内容,可以使用-o参数来指定输出位置,所有数据.bson文件中,可以使用bsondump工具检查结果,这里注意mongodump和mongorestore的版本最好要一致,并且注意选择secondary节点来备份,减少primary节点的压力,在备份复制集时,可以设置mongodump连接”setName/s1,s2,s3”, 它会自动选择一个可用的secondary进行备份。

3.4 备份脚本

简单写了一个备份脚本,可以借鉴使用

  1. #!/bin/bash
  2. ##This script is used to backup mongodb via mongodump and oplog
  3. Mongodump_path='/usr/local/mongodb/bin/mongodump'
  4. Port=27107
  5. Username=guest
  6. Password=123456
  7. Other_para='--oplog --quiet'
  8. Dump_dir=dump
  9. #Start backup
  10. if [ -d $Dump_dir ];then
  11. rm -fr $Dump_dir
  12. $Mongodump_path --port=$Port -u=$Username -p=$Password $Other_para
  13. else
  14. $Mongodump_path --port=$Port -u=$Username -p=$Password $Other_para
  15. fi
  16. #Package dump dir and mv to backu_path
  17. tar zcf mongodb_backup.tar.gz ./$Dump_dir
  18. rm -fr $Dump_dir
  19. mv -f mongodb_backup.tar.gz /ROOT/BACKUP/mongodb

3.5恢复备份

  1. mongorestore -p 27017 dump

3.6误操作的时间点恢复

  • 由于使用了强大的oplog参数来备份,就可以实现恢复到任意一个时间点的数据,下面将详细说明操作过程。
  • oplog.bson可是包含了所有操作的,如果全盘恢复回去,就等于是先让时光倒流,再看悲剧重演一遍。心都碎了……这时候你需要一个新朋友,就是上面提到的–oplogLimit。它与–oplogReplay一起使用时,可以限制重放到的时间点。那么重要的问题就是如何找到灾难发生的时间点了。仍然是bsondump。如果你对Linux命令熟悉,可以在管道中直接操作。如果不行,那就先dump到文件中,再用文本编辑器打开慢慢找好了。我们需要找的内容是”op”:”d”,它表示进行了一次删除操作。可以发现,oplog.bson中有100000次删除操作,实际上是一条一条把记录删除掉,这也是为什么remove({})操作会这么慢。如果对一个集合进行drop()就会快得多,它进行的操作请读者自己尝试。
  1. $ bsondump oplog.bson | grep "\"op\":\"d\"" | head {"b":true,"h":{"$numberLong":"5331406427126597755"},"ns":"test.foo","o":{"_id":{"$oid":"5602cdf1befd4a4bfb4d149b"}},"op":"d","ts":{"$timestamp":{"t":1443024507,"i":1}},"v":2}

此条记录中我们需要的是红色的$timestamp部分,它代表的发生这个操作的时间,也正是我们的–oplogLimit需要传入的时间,只是格式稍稍有变:

  • 恢复备份前的内容
  1. $ mongorestore -h 127.0.0.1 --oplogReplay --oplogLimit "1443024507:1" dump/

其中1443024507即是
timestampt1

timestamp中的”i”。这样配置后oplog将会重放到这个时间点以前,即正好避开了第一条删除语句及其后面的操作,数据库停留在灾难前状态。验证一下:

0
未经许可,不得转载,否则将受到作者追究,博主联系方式见首页右上角
  • 转载请注明来源:mongodb复制集备份
  • 本文永久链接地址:http://www.52devops.com/chuck/1337.html

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论
取消评论
代码 贴图 加粗 链接 删除线 签到