【MongoDB】— MongoDB的OPlog企业应用和高级应
1 oplog详解
1.1 oplog介绍
Oplog是local库下的一个固定集合,Secondary就是通过查看Primary 的oplog这个集合来进行复制的。每个节点都有oplog,记录这从主节点复制过来的信息,这样每个成员都可以作为同步源给其他节点。
Oplog 的存在极大地方便了 MongoDB 副本集的各节点的数据同步,MongoDB 的主节点接收请求操作,然后在 Oplog 中记录操作,次节点异步地复制并应用这些操作。
Oplog 可以说是Mongodb Replication的纽带。用于存储 MongoDB 数据库所有数据的操作记录的(实际只记录增删改和一些系统命令操作,查是不会记录的),有点类似于 mysql 的 binlog 日志。
1.2 Oplog 的默认储存大小
对于 unix 系统和 windows 系统
Storage Engine | Default Oplog Size | Lower Bound | Upper Bound |
---|---|---|---|
In-Memory Storage Engine | 5% of physical memory | 50 MB | 50 GB |
WiredTiger Storage Engine | 5% of free disk space | 990 MB | 50 GB |
MMAPv1 Storage Engine | 5% of free disk space | 990 MB | 50 GB |
Oplog 存储在 local 库的 oplog.rs 集合里面。对于一般的线上环境来说,默认的 Oplog 值就已经足够了。当达到储存大小的日志时,新的记录会将老的记录覆盖。
但是我们系统中如果存在以下操作的话,那么我们就可能需要设置更大的 Oplog 值来避免数据的丢失(在副本集中数据同步过程):
- 一次更新多个文件
- 删除与插入同样数量的数据
- 大量地更新现有的数据
从MongoDB 4.0开始, Oplog 可以超过其配置的大小限制,以避免删除,
一旦mongod第一次创建了 Oplog ,通过更改--oplogSize
选项将不会影响 Oplog 的大小。replSetResizeOplog使您可以动态调整 Oplog 的大小,而无需重新启动该mongod
过程。
oplog 中每个操作都是 幂等性 的,也就是说,无论是对目标数据库应用一次还是多次,oplog操作都会产生相同的结果。这样就保证了数据的一致性。
1.3 副本集数据同步的过程
副本集中数据同步的详细过程:
Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败(只有当同步源的数据损坏或者数据与主节点不一致时才可能发生),则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作执行多次,与执行一次的效果是一样的。
作用:
1、当Primary进行写操作的时候,会将这些写操作记录写入Primary的Oplog 中,而后Secondary会将Oplog 复制到本机并应用这些操作,从而实现Replication的功能。
2、同时由于其记录了Primary上的写操作,故还能将其用作数据恢复。可以简单的将其视作Mysql中的binlog。
1.4 oplog的常用命令
注意事项:
1、在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改)。
2、oplog位于local库的db.oplog.rs。其中记录的是整个mongod数据实例一段时间内数据库的所有变更(插入/更新/删除)操作。
3、当oplog的空间用完时新记录自动覆盖最老的记录。其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,
所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。
常用命令:
登录副本集主节点
[mongod@mysql-master mult-mongodb]$ mongo 172.21.209.123:38019/admin
1、查看 Oplog 的状态:可以查看到评估的oplog的所用时间。
my_ReplSet1:PRIMARY> rs.printReplicationInfo()
configured oplog size: 2048MB
log length start to end: 92054secs (25.57hrs)
oplog first event time: Sat Sep 25 2021 08:45:10 GMT-0400 (EDT)
oplog last event time: Sun Sep 26 2021 10:19:24 GMT-0400 (EDT)
now: Sun Sep 26 2021 10:19:28 GMT-0400 (EDT)
my_ReplSet1:PRIMARY>
2、查看当前的 Oplog 存储设置的大小
my_ReplSet1:PRIMARY> use local
switched to db local
my_ReplSet1:PRIMARY> db.oplog.rs.stats().maxSize
NumberLong("2147483648")
3、查看 Oplog 最大大小和现在占用的大小,以及记录时长和时间
my_ReplSet1:PRIMARY> db.getReplicationInfo()
{
"logSizeMB" : 2048,
"usedMB" : 22.49,
"timeDiff" : 92184,
"timeDiffHours" : 25.61,
"tFirst" : "Sat Sep 25 2021 08:45:10 GMT-0400 (EDT)",
"tLast" : "Sun Sep 26 2021 10:21:34 GMT-0400 (EDT)",
"now" : "Sun Sep 26 2021 10:21:39 GMT-0400 (EDT)"
}
4、更改副本集成员的 Oplog 大小,更改的值要大于等于990MB,这里设置为1500MB。
my_ReplSet1:PRIMARY> db.adminCommand({replSetResizeOplog: 1, size: 15000})
{
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("7fffffff0000000000000001")
},
"lastCommittedOpTime" : Timestamp(1632666134, 1),
"$configServerState" : {
"opTime" : {
"ts" : Timestamp(1632666137, 1),
"t" : NumberLong(1)
}
},
"$clusterTime" : {
"clusterTime" : Timestamp(1632666137, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1632666134, 1)
}
my_ReplSet1:PRIMARY>
注意:
# 如果我们通过上面命令更改了 Oplog 的大小,系统是不会自动回收原始分配给 Oplog 的磁盘空间,我们需要使用 compact 来回收,在操作 compact 命令时,副本集成员是无法进行同步数据的。建议在进行回收的时候,不要对数据库进行写入,我们可以通过 rs.stepDown() 来关闭所有打开的连接。
use local
db.runCommand({ "compact" : "oplog.rs" })
# 执行报错的话 :"will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"
db.runCommand({ "compact" : "oplog.rs" ,"force":true})
1.5 oplog的日志数据结构即日志解析
oplog数据结构,oplog中字段的含义,通过下面的命令取出一条oplog:
my_ReplSet1:PRIMARY> db.oplog.rs.find().skip(1).limit(1).toArray()
[
{
"ts" : Timestamp(1632573921, 2),
"t" : NumberLong(1),
"h" : NumberLong(0),
"v" : 2,
"op" : "c",
"ns" : "config.$cmd",
"ui" : UUID("c781f024-4527-46fd-a448-8cbd8e46737b"),
"wall" : ISODate("2021-09-25T12:45:21.774Z"),
"o" : {
"create" : "transactions",
"idIndex" : {
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "config.transactions"
}
}
}
]
字段含义解析:
ts: 8字节的时间戳,由4字节unix timestamp + 4字节自增计数表示。这个值很重要,在选举(如master宕机时)新primary时,会选择ts最大的那个secondary作为新primary
op:1字节的操作类型
"i": insert
"u": update
"d": delete
"c": db cmd
"db":声明当前数据库 (其中ns 被设置成为=>数据库名称+ '.')
"n": no op,即空操作,其会定期执行以确保时效性
ns:操作所在的namespace
o:操作所对应的document,即当前操作的内容(比如更新操作时要更新的的字段和值)
o2: 在执行更新操作时的where条件,仅限于update时才有该属性。
2、oplog企业级应用
oplog企业集应用主要用于数据的备份和恢复。通过全量备份+增量备份+OPlog数据完成数据库的有效恢复,不会丢失数据。因此备份数据时,也必须对oplog进行备份,实现热备。备份时使用--oplog选项即可
。
应用方法:
1、准备测试数据
my_ReplSet1:PRIMARY>
my_ReplSet1:PRIMARY> show dbs
admin 0.000GB
config 0.001GB
local 0.003GB
ronnystack 0.002GB
my_ReplSet1:PRIMARY> use student
switched to db student
my_ReplSet1:PRIMARY> for(var i = 1 ;i < 100; i++) { db.grades.insert({id:i,coures:"Python",grade:100});}
WriteResult({ "nInserted" : 1 })
my_ReplSet1:PRIMARY> show tables
grades
my_ReplSet1:PRIMARY>
2、查看记录的日志
my_ReplSet1:PRIMARY> use local
switched to db local
my_ReplSet1:PRIMARY> db.oplog.rs.find().skip(1).limit(1).toArray()
[
{
"ts" : Timestamp(1632573921, 2),
"t" : NumberLong(1),
"h" : NumberLong(0),
"v" : 2,
"op" : "c",
"ns" : "config.$cmd",
"ui" : UUID("c781f024-4527-46fd-a448-8cbd8e46737b"),
"wall" : ISODate("2021-09-25T12:45:21.774Z"),
"o" : {
"create" : "transactions",
"idIndex" : {
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "config.transactions"
}
}
}
]
my_ReplSet1:PRIMARY>
3、oplog 配合mongodump实现热备
[mongod@mysql-master bak-mongodb]$ mongodump --port 38019 --oplog -o /data/mongodb/bak-mongodb
4、查看已备份的文件和数据库
[mongod@mysql-master bak-mongodb]$ ll
total 8
drwxrwxr-x 2 mongod mongod 69 Sep 26 10:47 admin
drwxrwxr-x 2 mongod mongod 4096 Sep 26 10:47 config
-rw-rw-r-- 1 mongod mongod 110 Sep 26 10:47 oplog.bson #备份的oplog二进制文件
drwxrwxr-x 2 mongod mongod 55 Sep 26 10:47 ronnystack
drwxrwxr-x 2 mongod mongod 53 Sep 26 10:47 student
作用介绍:--oplog 会记录备份过程中的数据变化。会以oplog.bson保存下来
5、故障恢复。
[mongod@mysql-master bak-mongodb]$ mongorestore --port 38019 --oplogReplay /data/mongodb/bak-mongodb
注:--oplogReplay用户恢复oplog日志,通过全备+增倍+Oplog日志实现企业级数恢复。
3、oplog高级应用
oplog高级应用是通过全备+增倍+Oplog日志实现企业级数恢复。
生产企业案例:
场景:某企业数据库每天0点对数据库做全量,oplog恢复窗口为48小时
某天上午10点student.users表的数据被开发人员误删除。
恢复思路:
1、停应用,挂维护页面
2、找测试库,并搭建测试环境
3、恢复昨天晚上0点的全备数据
4、截取全备之后到student.users误删除时间点的oplog,并恢复到测试库
5、将误删除表导出,恢复到生产库
故障恢复步骤
1、登录到数据库并创建备份目录
[mongod@mysql-master mongodb]$ mongo --port 38019 admin
[mongod@mysql-master bak-mongodb]$ [mongod@mysql-master bak-mongodb]$ mkdir -vp /data/mongodb/bak-mongodb
2、准备数据student库和grades文档。
[mongod@mysql-master bak-mongodb]$ for(var i = 1 ;i < 100; i++) { db.grades.insert({id:i,coures:"Python",grade:100});}
3、模拟全库做备份
[mongod@mysql-master bak-mongodb]$ rm -rf /data/mongodb/bak-mongodb/
[mongod@mysql-master bak-mongodb]$ mongodump --port 38019 --oplog -o /data/mongodb/bak-mongodb #备份全库
备份的文件目录
[mongod@mysql-master bak-mongodb]$ ll
total 8
drwxrwxr-x 2 mongod mongod 69 Sep 26 19:52 admin
drwxrwxr-x 2 mongod mongod 4096 Sep 26 19:52 config
-rw-rw-r-- 1 mongod mongod 110 Sep 26 19:52 oplog.bson
drwxrwxr-x 2 mongod mongod 55 Sep 26 19:52 ronnystack
drwxrwxr-x 2 mongod mongod 53 Sep 26 19:52 student
注:--oplog功能:在备份同时,将备份过程中产生的日志进行备份
文件必须存放在/data/mongodb/bak-mongodb下,自动命名为oplog.bson
4、模拟数据的增长
my_ReplSet1:PRIMARY> for(i=1;i<=1000;i++){ db.users.insert({"id":i,"name":"Ronny","addr":"sichuan","date":new Date()}); }
WriteResult({ "nInserted" : 1 })
my_ReplSet1:PRIMARY> for(i=1;i<=100;i++){ db.courses.insert({"id":i,"name":"Python","keshi":240,"date":new Date()}); }
WriteResult({ "nInserted" : 1 })
5、模拟误删除数据库
场景:上午10点,某开发人员误删除student库下的user表
元数据:
my_ReplSet1:PRIMARY> show dbs
admin 0.000GB
config 0.000GB
local 0.003GB
ronnystack 0.002GB
student 0.000GB
my_ReplSet1:PRIMARY> use student
switched to db student
my_ReplSet1:PRIMARY> show tables
courses
grades
users
my_ReplSet1:PRIMARY>
误删除模拟:
my_ReplSet1:PRIMARY> db.users.drop()
true
my_ReplSet1:PRIMARY>
my_ReplSet1:PRIMARY> show tables
courses
grades
my_ReplSet1:PRIMARY>
6、模拟。发现故障立即启动故障恢复方案。立即停库,停业务。
备份现有的数据和local库下的oplog.rs文档
[mongod@mysql-master student]$ mongodump --port 38019 -d local -c oplog.rs -o /data/mongodb/bak-mongodb
2021-09-26T20:04:34.740-0400 writing local.oplog.rs to /data/mongodb/bak-mongodb/local/oplog.rs.bson
2021-09-26T20:04:34.958-0400 done dumping local.oplog.rs (127999 documents)
7、截图oplog的数据,并恢复到删除之前的位置。
7.1 登陆到原数据库
[mongod@mysql-master bak-mongodb]$ mongo --port 38019 admin
7.2 查看获取数据库的oplog,此处获取一个文档。
my_ReplSet1:PRIMARY> use local
switched to db local
my_ReplSet1:PRIMARY> db.oplog.rs.find({op:"c"}).pretty();
{
"ts" : Timestamp(1632700901, 1),
"t" : NumberLong(1),
"h" : NumberLong(0),
"v" : 2,
"op" : "c",
"ns" : "student.$cmd",
"ui" : UUID("5ae40786-5938-43a8-9b8e-a4bd80f67298"),
"o2" : {
"numRecords" : 1000
},
"wall" : ISODate("2021-09-27T00:01:41.904Z"),
"o" : {
"drop" : "users"
}
}
my_ReplSet1:PRIMARY>
7.3 获取到oplog误删除时间点位置:
"ts" : Timestamp(1632700901, 1)
8、数据库恢复
方案:恢复全备备份+应用oplog
8.1、进入到备份目录下
[mongod@mysql-master bak-mongodb]$ ll
total 8
drwxrwxr-x 2 mongod mongod 69 Sep 26 19:52 admin
drwxrwxr-x 2 mongod mongod 4096 Sep 26 19:52 config
drwxrwxr-x 2 mongod mongod 57 Sep 26 20:04 local
-rw-rw-r-- 1 mongod mongod 110 Sep 26 19:52 oplog.bson
drwxrwxr-x 2 mongod mongod 55 Sep 26 19:52 ronnystack
drwxrwxr-x 2 mongod mongod 53 Sep 26 19:52 student
[mongod@mysql-master bak-mongodb]$ cd local/
[mongod@mysql-master local]$ ll
total 23644
-rw-rw-r-- 1 mongod mongod 24203894 Sep 26 20:04 oplog.rs.bson
-rw-rw-r-- 1 mongod mongod 142 Sep 26 20:04 oplog.rs.metadata.json
8.2 复制local库下的oplog.rs.bson到上一级目录下,会覆盖之前备份的oplog.bson。如需要,请备份。
[mongod@mysql-master local]$ cp oplog.rs.bson ../oplog.bson
8.3、删除备份的local库和表
[mongod@mysql-master local]$ rm -rf /data/mongodb/bak-mongodb/local/
8.4、恢复数据库,及恢复过程
#数据库的恢复,如果是生产环境,做好备份,请恢复到测试库中。本次是在原库恢复,因有幂等性,恢复比较慢。
[mongod@mysql-master bak-mongodb]$ mongorestore --port 38019 --oplogReplay --oplogLimit "1632700901:1" --drop /data/mongodb/bak-mongodb
2021-09-26T20:17:44.451-0400 preparing collections to restore from
2021-09-26T20:17:44.451-0400 don't know what to do with file "/data/mongodb/bak-mongodb/.oplog.bson.swp", skipping...
2021-09-26T20:17:44.461-0400 reading metadata for config.cache.chunks.config.system.sessions from /data/mongodb/bak-mongodb/config/cache.chunks.config.system.sessions.metadata.json
2021-09-26T20:17:44.513-0400 restoring config.cache.chunks.config.system.sessions from /data/mongodb/bak-mongodb/config/cache.chunks.config.system.sessions.bson
2021-09-26T20:17:44.526-0400 reading metadata for student.grades from /data/mongodb/bak-mongodb/student/grades.metadata.json
2021-09-26T20:17:44.526-0400 reading metadata for ronnystack.courses from /data/mongodb/bak-mongodb/ronnystack/courses.metadata.json
2021-09-26T20:17:44.551-0400 restoring student.grades from /data/mongodb/bak-mongodb/student/grades.bson
2021-09-26T20:17:44.561-0400 restoring ronnystack.courses from /data/mongodb/bak-mongodb/ronnystack/courses.bson
2021-09-26T20:17:44.562-0400 restoring indexes for collection ronnystack.courses from metadata
2021-09-26T20:17:44.841-0400 finished restoring ronnystack.courses (0 documents, 0 failures)
2021-09-26T20:17:44.861-0400 no indexes to restore
2021-09-26T20:17:44.861-0400 finished restoring student.grades (99 documents, 0 failures)
2021-09-26T20:17:44.862-0400 reading metadata for config.cache.chunks.ronnystack.courses from /data/mongodb/bak-mongodb/config/cache.chunks.ronnystack.courses.metadata.json
2021-09-26T20:17:44.907-0400 restoring config.cache.chunks.ronnystack.courses from /data/mongodb/bak-mongodb/config/cache.chunks.ronnystack.courses.bson
2021-09-26T20:17:44.913-0400 reading metadata for config.cache.collections from /data/mongodb/bak-mongodb/config/cache.collections.metadata.json
2021-09-26T20:17:44.917-0400 reading metadata for config.cache.databases from /data/mongodb/bak-mongodb/config/cache.databases.metadata.json
2021-09-26T20:17:44.950-0400 restoring config.cache.collections from /data/mongodb/bak-mongodb/config/cache.collections.bson
2021-09-26T20:17:44.965-0400 restoring indexes for collection config.cache.chunks.config.system.sessions from metadata
2021-09-26T20:17:44.967-0400 restoring indexes for collection config.cache.chunks.ronnystack.courses from metadata
2021-09-26T20:17:44.973-0400 restoring config.cache.databases from /data/mongodb/bak-mongodb/config/cache.databases.bson
2021-09-26T20:17:45.024-0400 no indexes to restore
2021-09-26T20:17:45.024-0400 finished restoring config.cache.collections (2 documents, 0 failures)
2021-09-26T20:17:45.026-0400 no indexes to restore
2021-09-26T20:17:45.026-0400 finished restoring config.cache.databases (2 documents, 0 failures)
2021-09-26T20:17:45.038-0400 finished restoring config.cache.chunks.ronnystack.courses (4 documents, 0 failures)
2021-09-26T20:17:45.040-0400 finished restoring config.cache.chunks.config.system.sessions (1024 documents, 0 failures)
2021-09-26T20:17:45.040-0400 replaying oplog
2021-09-26T20:17:47.451-0400 oplog 970KB
2021-09-26T20:17:50.451-0400 oplog 2.44MB
2021-09-26T20:17:53.451-0400 oplog 3.59MB
2021-09-26T20:17:56.451-0400 oplog 4.75MB
2021-09-26T20:17:59.451-0400 oplog 5.87MB
2021-09-26T20:18:02.451-0400 oplog 6.98MB
2021-09-26T20:18:05.451-0400 oplog 8.08MB
2021-09-26T20:18:08.451-0400 oplog 9.18MB
2021-09-26T20:18:11.451-0400 oplog 10.3MB
2021-09-26T20:18:14.451-0400 oplog 11.4MB
2021-09-26T20:18:17.451-0400 oplog 12.6MB
2021-09-26T20:18:20.451-0400 oplog 13.6MB
2021-09-26T20:18:23.451-0400 oplog 14.5MB
2021-09-26T20:18:26.451-0400 oplog 15.4MB
2021-09-26T20:18:29.451-0400 oplog 16.1MB
2021-09-26T20:18:32.451-0400 oplog 17.0MB
2021-09-26T20:18:35.451-0400 oplog 17.9MB
2021-09-26T20:18:38.451-0400 oplog 18.8MB
2021-09-26T20:18:41.451-0400 oplog 19.7MB
2021-09-26T20:18:44.451-0400 oplog 20.5MB
2021-09-26T20:18:47.451-0400 oplog 21.3MB
2021-09-26T20:18:50.451-0400 oplog 23.1MB
2021-09-26T20:18:50.523-0400 applied 114582 oplog entries
2021-09-26T20:18:50.523-0400 oplog 23.1MB
2021-09-26T20:18:50.523-0400 1131 document(s) restored successfully. 0 document(s) failed to restore.
[mongod@mysql-master bak-mongodb]$
注意:--oplogLimit "1632700901:1" 的格式和位置。
8.5、登录到数据库并验证数据
my_ReplSet1:PRIMARY> use student
switched to db student
my_ReplSet1:PRIMARY> show tables
courses
grades
users
my_ReplSet1:PRIMARY> db.users.count()
1000
my_ReplSet1:PRIMARY>
4 分片集群备份
思考:分片集群是分布式,如何进行备份有效恢复,制定备份方案。
4.1、分片集群要备份什么?
根据分片集群的结构组成,分为三部分:mongos、config server和shard 。
mongos是作为路由,不存储数据。因此,需要备份config server和shard 节点,
4.2 、单独进行备份
备份有什么困难和问题
(1)chunk迁移的问题
人为控制在备份的时候,避开迁移的时间窗口
(2)shard节点之间的数据不在同一时间点。
选业务量较少的时候
4.3 、了解Ops Manager ,用于分片备份,监控,优化等。
至此:MongoDB的OPlog和备份恢复案例演示完毕。