暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MongoDB之增量备份

4392

要实现数据库增量备份一般是基于物理备份来实现,比如PostgreSQL的连续归档备份。但是MongoDB官方没有提供物理备份工具,只提供了逻辑备份工具:mongoexport和mongodump,而逻辑备份是一般是无法实现增量备份。

但是MongoDB副本集架构中,提供了Oplog集合来存储所有的数据变更操作,并且具有幂等性,可以利用它来做数据增量备份和恢复。

oplog是什么

Oplog是副本集架构下local库下的一个固定集合oplog.rs,Oplog存储了MongoDB数据库所发生的操作记录。MongoDB主节点和从节点之间数据同步就是基于oplog来做的。当Primary进行写操作的时候,会将这些写操作记录写入Primary的Oplog中,而后Secondary会将Oplog复制到本机,并应用这些操作。

Oplog集合本身是一个Capped Table(固定大小集合),它只能保存特定数量的操作日志,通常oplog使用空间的增长速度跟系统处理写请求的速度相当。

可以通过rs.printReplicationInfo()可以用来查看oplog的大小,操作日志的起始时间。

replSet1:PRIMARY> db.getReplicationInfo()
{
 "logSizeMB" : 2048,
 "usedMB" : 2046.72,
 "timeDiff" : 35306150,
 "timeDiffHours" : 9807.26,
 "tFirst" : "Thu Sep 17 2020 01:33:48 GMT+0800 (CST)",
 "tLast" : "Sat Oct 30 2021 16:49:38 GMT+0800 (CST)",
 "now" : "Sat Oct 30 2021 16:49:46 GMT+0800 (CST)"
}

字段说明:

configured oplog size:oplog文件大小,单位是MB;
log length start to end: oplog日志的启用时间段;
oplog first event time: 第一个事务日志的产生时间;
oplog last event time: 最后一个事务日志的产生时间;
now: 现在的时间;

也可以使用db.getReplicationInfo()来查看oplog的状态、大小、存储的时间范围。

replSet1:PRIMARY> rs.printReplicationInfo()
configured oplog size:   2048MB
log length start to end: 35306860secs (9807.46hrs)
oplog first event time:  Thu Sep 17 2020 01:33:48 GMT+0800 (CST)
oplog last event time:   Sat Oct 30 2021 17:01:28 GMT+0800 (CST)
now:                     Sat Oct 30 2021 17:01:30 GMT+0800 (CST)

oplog各字段含义

Capped collections可以使用$natural操作符按插入顺序的正序或反序返回结果:

use local
db.oplog.rs.find({}).sort({$natural: -1}).limit(1)

我们使用上述命令查询最新一条oplog文档。

replSet1:PRIMARY> db.oplog.rs.find({}).sort({$natural: -1}).limit(1).pretty()
{
 "ts" : Timestamp(1635509740, 2),
 "t" : NumberLong(78),
 "h" : NumberLong(0),
 "v" : 2,
 "op" : "u",
 "ns" : "zz.a_test",
 "ui" : UUID("560a8f7e-f813-48dd-9d82-66b0f12397f0"),
 "o2" : {
  "_id" : ObjectId("60df16788d251d0010445c1c")
 },
 "wall" : ISODate("2021-10-29T12:15:40.267Z"),
 "o" : {
  "_id" : ObjectId("60df16788d251d0010445c1c"),
  "bizSpace" : "cs",
  "projectKey" : "1000",
  "functionPointName" : "编辑",
  "pid" : "60df16788d251d0010445c19",
  "position" : 3,
  "permissionKey" : "agentAccount:update",
  "hasDataPermission" : false,
  "isDelete" : NumberLong(0),
  "gmtCreate" : ISODate("2021-07-02T13:36:56.412Z"),
  "gmtModified" : ISODate("2021-07-02T13:36:56.412Z")
 }
}

字段含义:

  • ts: 操作的时间戳,64位表示,高32位是时间戳,低32位是计数累加。
  • t: election term。对应raft协议里面的term,每次发生节点down掉,新节点加入,主从切换,term都会自增。
  • h: 操作的全局唯一id的hash结果。
  • v: oplog的版本字段。
  • op: 具体操作类型。"i"表示插入,"d"表示删除,"u"表示更新,"c"表示是DDL操作,"n"表示是空消息(可以看作是心跳oplog)。
  • ns: 命名空间。操作发生在哪个表上面。
  • o: 具体的操作指令字段。对于op=i,这里表示插入的内容;op=d,这里表示要删除的文档;op=u,这里表示更新后的内容。
  • o2: 查询字段,只存在于op=u的情况,指定要操作的文档。

oplog增量备份

所谓备份即意味着转储,而增量备份(incremental backup)是备份的一个类型,是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的部分。

前面我们说到oplog是一个集合,那么我们可以使用mysqldump对其进行备份。

mysqldump命令

语法:

mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 集合 -o 文件存在路径

其中:
--db , -d :指定要备份的数据库。如果未指定,则会备份所有数据库。
--collection , -c :指定要备份的集合。如果未指定,则会备份所有集合。
--gzip:压缩备份文件。压缩输出,如果mongodump指定导出到目录,则该选项会将每个文件都压缩,并添加.gz后缀。如果mongodump指定导出到文档或标准输出流,则该选项会压缩到文档或输出流中。
--out , -o :指定备份路径。如不指定,则mongodump默认将文件输出到dump所在的工作目录中。该选项不能和--archive一起使用。
--archive :将备份内容写入单个文件或标准输出。

开始增量备份:

1)首先我们需要上一次全备或增量备份后的时间戳,以确定增量备份的开始时间。

问题是怎么获取这个时间戳呢?

假如是全备结束,我们想看全备结束时的时间戳,可以给mongodump设置参数--oplog,该参数会在备份路径下产生一个oplog.bson文件,里面存放了开始进行dump到dump结束之间所有的op log操作,如下图所示:

图片来源:https://www.w3xue.com/exp/article/201811/7362.html

mongodump -u root -p root  -o /tmp/mongo_dump --oplog

oplog.bson文件是bson格式的,没有办法直接查看,打开是乱码,我们可以使用bsondump将bson转化为json格式。

./bsondump /tmp/mongo_dump/oplog.bson
{"ts":{"$timestamp":{"t":1635651513,"i":1}},"t":{"$numberLong":"28"},"h":{"$numberLong":"-611837201367149992"},"v":2,"op":"n","ns":"","wall":{"$date":"2021-10-31T03:38:33.705Z"},"o":{"msg":"periodic noop"}}

得到的时间戳是:{"ts":{"$timestamp":{"t":1635651513,"i":1}}

2)导出新的oplog(增量)。

我们已经知道了上次全备后的时间戳,那么我们就可以使用条件,{ts:{$gt: Timestamp(1635651513, 1)}},导出自上次备份结束,截止到目前的所有oplog记录。

mongodump -u root -p root -d local -c oplog.rs -q '{ts:{$gt: Timestamp(1635651513, 1)}}' -o /tmp/mongo_oplogBack --authenticationDatabase admin
2021-10-31T11:52:29.847+0800 writing local.oplog.rs to
2021-10-31T11:52:29.902+0800 done dumping local.oplog.rs (83 documents)

注:--q指定的时间戳可以比全量开始时间提前几秒,以防止数据丢失,因为oplog的幂等性,这并不影响MongoDB恢复数据。

看下增量备份生成的文件。

ls /tmp/mongo_oplogBack/
local
ls /tmp/mongo_oplogBack/local
oplog.rs.bson  oplog.rs.metadata.json

此处的oplog.rs.bson可以基本类比于全备过程中产生的oplog.bson,我们也可以使用bsondump来解析这个文件,获取这次增量备份后的时间戳。

3)增量恢复。

拿到了oplog的增量备份数据,我们就可以结合mongorestore工具,进行增量恢复。

mongorestore --host xxx --port xxx --oplogReplay /tmp/mongo_oplogBack/local/oplog.rs.bson

线上业务不断有写入,也即oplog是不断的追加的,但是oplog大小是固定的。如果想让目标端与源保持数据同步就需要对oplog进行持续的增量备份,或者如果想做按时间点恢复,也需要保证是oplog是连续的。

这里有一个关键点,就是增量备份频率的设置。因为oplog的大小是固定的,很可能出现在增量备份间隔内,出现oplog被覆盖的情况,那么这时候备份的oplog数据就是不完整的,也将导致利用它恢复出的数据是不完整的。

所以我们需要评估业务的写入压力,比如单位时间内产生多少日志,来合理设置oplog的大小,如果系统磁盘充足,可以将oplog集合设置的大些。

参考文档:

https://tech.willhaben.at/mongodb-incremental-backups-dff4c8f54d58

https://www.w3xue.com/exp/article/201811/7362.html

文章转载自PostgreSQL运维技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论