作者:任坤

现居珠海,先后担任专职 Oracle 和 MySQL DBA,现在主要负责 MySQL、mongoDB 和 Redis 维护工作。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


1 背景

网上基于 mongo 单实例 PITR 的案例比较多,官档也有关于mongo cluser 的恢复步骤,但于基于 mongo cluster 的 PITR 案例几乎没有。本文基于实验环境,模拟线上环境完成一次针对 mongo cluster 的 PITR 。

原集群实例分布情况:

172.16.129.170 shard1 27017 shard2 27018 config 37017 mongos 47017
172.16.129.171 shard1 27017 shard2 27018 config 37017 mongos 47017
172.16.129.172 shard1 27017 shard2 27018 config 37017 mongos 47017

考虑到线上环境的实际数据会比较大,这里只将 shard 恢复成单实例,能供开发查询数据即可。 恢复后的实例分布情况:

172.16.129.173 shard1 27017 shard2 27018 config 37017 mongos 47017
172.16.129.174 config 37017
172.16.129.175 config 37017

mongo 版本为 percona 4.2.13,对每个 shard 实例和 config server 都部署 hot backup 定时备份脚本,同时对每个 shard 实例和 config server 部署 oplog 定时备份脚本。 构建测试数据,通过 mongos 登录集群,创建一个 hash 分片表并插入10条数据:

use admin
db.runCommand({"enablesharding":"renkun"})
sh.shardCollection("renkun.user", { id: "hashed" } )
use renkun
var tmp = [];
for(var i =0; i<10; i++){
tmp.push({ 'id':i, "name":"Kun " + i});
}
db.user.insertMany(tmp);

对 shard1 、shard2 和 config server 执行物理热备,继续插入数据:

use renkun
var tmp = [];
for(var i =10; i<20; i++){
tmp.push({ 'id':i, "name":"Kun " + i});
}
db.user.insertMany(tmp);

对 shard 、shard2 和 config server 进行 oplog 备份,oplog 备份文件里包含了以上所有操作。 此时 user 表有20条数据,并且 id 从0-20依次递增。我们的要求是将集群恢复到 max(id)=15 时的快照点。

官档给出的步骤是依次恢复出 config server、shard 和 mongo ,但是官档上没有前滚 oplog 的操作。

我们的案例中需要先从 shard 的 oplog 文件中解析出待恢复的时间点,因此调整一下顺序,先恢复 shard 再恢复 config server 。

2 恢复 shard 单实例

将 shard 的物理备份和 oplog 备份传输到目标机器,物理备份直接解压到数据目录即可启动。

2.1 确认待恢复快照点

对两个 shard 的 oplog 备份分别执行如下操作

bsondump oplog.rs.bson > oplog.rs.json
more oplog.rs.json | egrep "\"op\"\:\"\i\",\"ns\":\"renkun\.user\"" | grep "\"Kun
15\""

在 shard2 的 oplog 备份上查询到

{"ts":{"$timestamp":{"t":1623408268,"i":6}},"t":{"$numberLong":"1"},"h":
{"$numberLong":"0"},"v":{"$numberInt":"2"},"op":"i","ns":"renkun.user","ui":{"$binary":
{"base64":"uhlG0e4sRB+RUfFOzpMCEQ==","subType":"04"}},"wall":{"$date":
{"$numberLong":"1623408268694"}},"o":{"_id":{"$oid":"60c33e8c1c3edd59f25eecb5"},"id":
{"$numberDouble":"15.0"},"name":"Kun 15"}}

由此确认 id=15 插入时对应的时间戳为1623408268:6 ,但是 mongorestore 的–oplogLimit 指定的时间戳参数为开区间,即不会重放指定时间戳对应的 oplog entry ,因此要想恢复到这个时间点就必须对其再加1位,于是变成了1623408268:7 。

2.2 创建临时账号

用 root 账号登录 shard 实例,创建 1 个具有 __system 角色的用户,命名为 internal_restore 。 这个用户不仅用于前滚 oplog ,还用于修改 admin.system.version 以及删除 local db,root 账号默认没有权限执行这些操作。

use admin
db.createUser( { user: "internal_restore", pwd: "internal_restore", roles: [
"__system" ] })

用internal_restore登录两个shard实例,删除local db 。

use local
db.dropDatabase()

2.3 前滚oplog至指定时间点

mongorestore ‐h 127.0.0.1 ‐uinternal_restore ‐p"internal_restore" ‐‐port 27017 ‐‐
oplogReplay ‐‐oplogLimit "1623408268:7" ‐‐authenticationDatabase admin
/data/backup/202106111849_27017/local/oplog.rs.bson
mongorestore ‐h 127.0.0.1 ‐uinternal_restore ‐p"internal_restore" ‐‐port 27018 ‐‐
oplogReplay ‐‐oplogLimit "1623408268:7" ‐‐authenticationDatabase admin
/data/backup/202106111850_27018/local/oplog.rs.bson

分别登录 shard1 和 shard2 查看数据:

‐‐shard1 27017
> db.user.find().sort({"id":1})
{ "_id" : ObjectId("60c330322424943565780766"), "id" : 3, "name" : "Kun 3" }
{ "_id" : ObjectId("60c330322424943565780769"), "id" : 6, "name" : "Kun 6" }
{ "_id" : ObjectId("60c33032242494356578076b"), "id" : 8, "name" : "Kun 8" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb1"), "id" : 11, "name" : "Kun 11" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb2"), "id" : 12, "name" : "Kun 12" }
‐‐shard2 27018
> db.user.find().sort({"id":1})
{ "_id" : ObjectId("60c330322424943565780763"), "id" : 0, "name" : "Kun 0" }
{ "_id" : ObjectId("60c330322424943565780764"), "id" : 1, "name" : "Kun 1" }
{ "_id" : ObjectId("60c330322424943565780765"), "id" : 2, "name" : "Kun 2" }
{ "_id" : ObjectId("60c330322424943565780767"), "id" : 4, "name" : "Kun 4" }
{ "_id" : ObjectId("60c330322424943565780768"), "id" : 5, "name" : "Kun 5" }
{ "_id" : ObjectId("60c33032242494356578076a"), "id" : 7, "name" : "Kun 7" }
{ "_id" : ObjectId("60c33032242494356578076c"), "id" : 9, "name" : "Kun 9" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb0"), "id" : 10, "name" : "Kun 10" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb3"), "id" : 13, "name" : "Kun 13" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb4"), "id" : 14, "name" : "Kun 14" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb5"), "id" : 15, "name" : "Kun 15" }

数据已恢复完成,总共16条,max(id)=15

2.4 修改 admin.system.version

shard 由原来的3节点复制集变成了单实例,host ip 也发生了改变,因此要修改对应的元数据信息。以 internal_restore 用户登录两个 shard 实例,分别执行:

use admin
db.system.version.deleteOne( { _id: "minOpTimeRecovery" } )
db.system.version.find( {"_id" : "shardIdentity" } )
db.system.version.updateOne({ "_id" : "shardIdentity" },
{ $set :
{ "configsvrConnectionString" :
"configdb/172.16.129.173:37017,172.16.129.174:37017,172.16.129.175:37017"}
}
)

在被删除和修改之前,这两条记录分别存储的还是老的 config server 信息,详情如下:

{ "_id" : "shardIdentity", "shardName" : "repl", "clusterId" :
ObjectId("60c2c9b44497a4f2e02510fd"), "configsvrConnectionString" :
"configdb/172.16.129.170:37017,172.16.129.171:37017,172.16.129.172:37017" }
{ "_id" : "minOpTimeRecovery", "configsvrConnectionString" :
"configdb/172.16.129.170:37017,172.16.129.171:37017,172.16.129.172:37017", "minOpTime" :
{ "ts" : Timestamp(1623383008, 6), "t" : NumberLong(1) }, "minOpTimeUpdaters" : 0,
"shardName" : "repl" }

至此2个 shard server 已经完成恢复,下一步是恢复 config server 。

3 恢复 config server

将物理备份传输到目标机器,直接解压到数据目录即可用。 首先以单实例身份启动 config server ,用 root 账号登录后,创建1个具有__system角色的用户(同上)。

3.1 前滚 oplog

mongorestore ‐h 127.0.0.1 ‐uinternal_restore ‐p"internal_restore" ‐‐port 37017 ‐‐
oplogReplay ‐‐oplogLimit "1623408268:7" ‐‐authenticationDatabase admin
/data/backup/202106111850_37017/local/oplog.rs.bson

3.2 修改元数据

以 interal_restore 身份登录实例,修改集群的 shard 元数据信息,具体操作如下:

use local
db.dropDatabase()
use config
db.shards.find()
db.shards.updateOne({ "_id" : "repl" }, { $set : { "host" : "172.16.129.173:27017" } })
db.shards.updateOne({ "_id" : "repl2" }, { $set : { "host" : "172.16.129.173:27018" } })
db.shards.find()

3.3 启动集群

关闭 config server ,以集群模式启动,对应的配置文件开启如下参数:

sharding:
clusterRole: configsvr
replication:
oplogSizeMB: 10240
replSetName: configdb

登录后执行

rs.initiate()
rs.add("172.16.129.174:37017")
rs.add("172.16.129.175:37017")

此时 config server 变成1个3节点集群,也恢复完毕。

4 配置 mongos

可以直接把原环境的 mongos 配置文件复制过来,只需要修改一下 sharding 和 bindIp 参数即可

sharding:
configDB: "configdb/172.16.129.173:37017,172.16.129.174:37017,172.16.129.175:37017"
net:
port: 47017
bindIp: 127.0.0.1,172.16.129.173

启动后登录 mongos 查询 user 表,总共16条记录,max(id)=15,符合预期结果。

mongos> use renkun
switched to db renkun
mongos> db.user.find().sort({"id":1})
{ "_id" : ObjectId("60c330322424943565780763"), "id" : 0, "name" : "Kun 0" }
{ "_id" : ObjectId("60c330322424943565780764"), "id" : 1, "name" : "Kun 1" }
{ "_id" : ObjectId("60c330322424943565780765"), "id" : 2, "name" : "Kun 2" }
{ "_id" : ObjectId("60c330322424943565780766"), "id" : 3, "name" : "Kun 3" }
{ "_id" : ObjectId("60c330322424943565780767"), "id" : 4, "name" : "Kun 4" }
{ "_id" : ObjectId("60c330322424943565780768"), "id" : 5, "name" : "Kun 5" }
{ "_id" : ObjectId("60c330322424943565780769"), "id" : 6, "name" : "Kun 6" }
{ "_id" : ObjectId("60c33032242494356578076a"), "id" : 7, "name" : "Kun 7" }
{ "_id" : ObjectId("60c33032242494356578076b"), "id" : 8, "name" : "Kun 8" }
{ "_id" : ObjectId("60c33032242494356578076c"), "id" : 9, "name" : "Kun 9" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb0"), "id" : 10, "name" : "Kun 10" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb1"), "id" : 11, "name" : "Kun 11" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb2"), "id" : 12, "name" : "Kun 12" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb3"), "id" : 13, "name" : "Kun 13" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb4"), "id" : 14, "name" : "Kun 14" }
{ "_id" : ObjectId("60c33e8c1c3edd59f25eecb5"), "id" : 15, "name" : "Kun 15" }

至此,一个完整的 mongo cluster pitr 操作正式完成。

5 总结

mongo 4.X 开始引入事务,尤其是4.2支持跨分片事务,按照官档介绍恢复事务涉及的数据必须要用指定工具,上述操作暂不适用。

技术分享 | 基于 mongo cluster 的 PITR 恢复案例一则相关推荐

  1. 技术分享 | 基于 Alertmanager 告警系统的改造

    作者:莫善 某互联网公司高级 DBA. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源. 一.引言 告警跟运维工作息息相关,一个好的告警系统不仅能提升 ...

  2. 技术分享 | 基于EOS的Dapp开发

    区块链技术是当前最能挑动社会舆论神经,激起资本欲望的现象级技术.去中心化的价值互联,信用共识,新型组织构架,新的生产关系和智能合约,颠覆法币的发行流通体系和记账体系.这些新的技术都让人充满想象,充满向 ...

  3. sql 拆分_技术分享 | 基于分布式中间件的SQL改造指南

    原创作者: 孙正方 4月12日,GOPS全球运维大会在深圳隆重召开,全球运维大会是国内第一个运维行业大会,爱可开源社区在基础架构及DevOps解决方案专场分享了<基于分布式中间件的SQL改造指南 ...

  4. 技术分享 | 基于室外RTK/GPS定位系统下的无人机集群协同

    在自然界中,为弥补个体能力的不足,诸多生物种群能通过个体相互之间的交流与合作呈现出某种群体行为,比如鱼群结群游弋.鸟群聚集迁徙以及蚂蚁协同搬运等.受此激励,人们希望开发像鸟群.鱼群一样自由集结可以执行 ...

  5. 技术分享| 基于 Etcd 的分布式锁实现原理及方案

    1. 为什么选择 Etcd 据官网介绍,Etcd 是一个分布式,可靠的 Key-Value 存储系统,主要用于存储分布式系统中的关键数据.初见之下,Etcd 与 NoSQL 数据库系统有几分相似,但作 ...

  6. 基于python的搜索引擎论文_技术分享 - 基于python构建搜索引擎系列——(四)检索模型...

    构建好倒排索引之后,就可以开始检索了. 检索模型有很多,比如向量空间模型.概率模型.语言模型等.其中最有名的.检索效果最好的是基于概率的BM25模型. 给定一个查询Q和一篇文档d,d对Q的BM25得分 ...

  7. 上海航芯技术分享 | 基于SPI Flash的U盘程序,从STM32F103到ACM32F403

    前言 本项目是以SPI Flash(如W25Q128等)存储元件作为存储单元,MCU主控完成USB接口通信并根据SCSI协议实现U盘功能.其结构如下图所示: SPI Flash部分移植 SPI功能部分 ...

  8. 银行客户用户画像_技术分享 | 基于数据中台的银行客户画像体系构建

    背景 1.金融消费行为的改变,企业无法接触到客户 80后.90后总计3.4亿人口,日益成为金融企业主要的消费者,但是他们的金融消费习惯正在改变,他们不愿意到金融网点办理业务,不喜欢被动接受金融产品和服 ...

  9. 技术分享| 基于RTM 实现的呼叫邀请如何添加推送功能?

    RTM 实时消息服务,解决了在线实时信令的传递,如何配合推送服务,去做离线通知功能一直困扰着开发者,本文从 RTM 的功能以及响应机制入手,教大家如何通过RTM配合第三方推送服务来完成离线消息通知. ...

最新文章

  1. 毕飞宇:我是靠阅读支撑起来的作家 因为生活没有给我那么多
  2. python语言必背代码-Python入门必须知道的11个知识点
  3. Android回调的简单理解
  4. 思科asa5515端口映射_Cisco ASA端口映射
  5. ant design form表单的时间处理
  6. Ubuntu android 开发配置
  7. python提取txt中指定内容_提取视频中的音频,Python三行程序搞定!
  8. 猿辅导 python_关于猿辅导机器学习项目ytk-learn和ytk-mp4j分布式机器学习库
  9. SQL Server 2005 性能优化实战系列(文章索引)
  10. html里文字跳动,Web前端
  11. css3中的background的新特性background-origin,background-clip,background-size详解
  12. PSFTP工具的使用教程
  13. mysql查询数据教程_mysql数据库的查询
  14. R语言使用order函数对dataframe数据进行排序、基于多个字段(变量)进行降序排序(DESCENDING)
  15. Android Studio的复制一行快捷键与Windows7屏幕旋转快捷键冲突
  16. 鼠标垫测试软件,百款鼠标垫测试(项目)
  17. python pyz_Python pyzgoubi包_程序模块 - PyPI - Python中文网
  18. 天龙架设linux环境配置,《果子资源》-天龙八部-手工纯端架设教程 - T-天龙八部 - Powered by Discuz!...
  19. Laravel表单验证,优雅一点的写法,控制器里面不要写太多东西,
  20. 计算机教师面试万能稿,教资面试——信息技术试讲逐字稿

热门文章

  1. 淘宝为什么能成为阿里巴巴的创新基地? | 一点财经
  2. 深度学习算法评价标准AP bbox bev 3d
  3. 群狼调研开展深圳市某区开展控烟工作暗访
  4. 关于多线程中sleep、join、yield的区别
  5. Vue2自定义指令directives简介
  6. OpenGL文字写入
  7. 测试基础+计算机基础
  8. 安卓中的虚拟手机莫名其妙出现问题,百度了好久,最终还是不管用。最终得到了来自陌生人的指导,希望我发布的这篇文章能将这份凌晨的温暖传递下去。也在此对这位陌生人表示真挚的感谢。
  9. [蓝桥杯][基础训练]2n皇后问题
  10. 云服务器安装exe文件,云服务器 安装exe