MongoDB oplog详解
MongoDB oplog详解
1:oplog简介
oplog是local库下的一个固定集合,Secondary就是通过查看Primary 的oplog这个集合来进行复制的。每个节点都有oplog,记录这从主节点复制过来的信息,这样每个成员都可以作为同步源给其他节点。
MongoDB Oplog(操作日志)是 MongoDB 中的一个特殊集合,用于记录所有数据库操作的更改。Oplog 以循环缓冲区的方式工作,当达到指定大小后,会覆盖最旧的操作日志。通过读取 Oplog 中的操作记录,可以实现数据的复制、故障恢复和实时监控等功能。
Oplog 是 MongoDB 的一个内部集合,以 “oplog.rs” 的形式存在于 local 数据库中。Oplog 集合中的每个文档都表示一个数据库操作,包括插入、更新和删除等操作。每个操作都包含操作类型、操作时间、操作的命名空间以及操作的详细信息等字段。
Oplog 可以说是Mongodb Replication的纽带了。
2:副本集数据同步的过程
副本集中数据同步的详细过程:Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败(只有当同步源的数据损坏或者数据与主节点不一致时才可能发生),则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作执行多次,与执行一次的效果是一样的。
作用:
- 当Primary进行写操作的时候,会将这些写操作记录写入Primary的Oplog 中,而后Secondary会将Oplog 复制到本机并应用这些操作,从而实现Replication的功能。
- 同时由于其记录了Primary上的写操作,故还能将其用作数据恢复。
- 可以简单的将其视作Mysql中的binlog
3:oplog的增长速度
oplog是固定大小,他只能保存特定数量的操作日志,通常oplog使用空间的增长速度跟系统处理写请求的速度相当,如果主节点上每分钟处理1KB的写入数据,那么oplog每分钟大约也写入1KB数据。如果单次操作影响到了多个文档(比如删除了多个文档或者更新了多个文档)则oplog可能就会有多条操作日志。db.testcoll.remove() 删除了1000000个文档,那么oplog中就会有1000000条操作日志。如果存在大批量的操作,oplog有可能很快就会被写满了。(和mysql的binlog的ROW格式一样,会记录数据的变更)
大小:
Oplog 是一个capped collection。
在64位的Linux, Solaris, FreeBSD, and Windows 系统中,Mongodb默认将其大小设置为可用disk空间的5%(默认最小为1G,最大为50G),或也可以在mongodb复制集实例初始化之前将mongo.conf中oplogSize设置为我们需要的值。
local.oplog.rs 一个capped collection集合.可在命令行下使用--oplogSize 选项设置该集合大小尺寸.
但是由于Oplog 其保证了复制的正常进行,以及数据的安全性和容灾能力
4:oplog注意事项:
local.oplog.rs特殊的集合。用来记录Primary节点的操作。
为了提高复制的效率,复制集中的所有节点之间会相互的心跳检测(ping)。每个节点都可以从其他节点上获取oplog。
oplog中的一条操作。不管执行多少次效果是一样的
5:oplog的大小
Oplog 存储在 local 库的 oplog.rs 集合里面。对于一般的线上环境来说,默认的 Oplog 值就已经足够了。当达到储存大小的日志时,新的记录会将老的记录覆盖。
但是我们系统中如果存在以下操作的话,那么我们就可能需要设置更大的 Oplog 值来避免数据的丢失(在副本集中数据同步过程):
- 一次更新多个文件
- 删除与插入同样数量的数据
- 大量地更新现有的数据
从MongoDB 4.0开始, Oplog 可以超过其配置的大小限制,以避免删除
一旦mongod第一次创建了 Oplog ,更改--oplogSize选项将不会影响 Oplog 的大小。replSetResizeOplog使您可以动态调整 Oplog 的大小,而无需重新启动该mongod过程。
oplog 中每个操作都是 幂等性 的,也就是说,无论是对目标数据库应用一次还是多次,oplog操作都会产生相同的结果。这样就保证了数据的一致性
- 第一次启动复制集中的节点时,MongoDB会建立Oplog,会有一个默认的大小,这个大小取决于机器的操作系统
- rs.printReplicationInfo() 查看 oplog 的状态,输出信息包括 oplog 日志大小,操作日志记录的起始时间。
- db.getReplicationInfo() 可以用来查看oplog的状态、大小、存储的时间范围。
oplog的大小
capped collection是MongoDB中一种提供高性能插入、读取和删除操作的固定大小集合,当集合被填满的时候,新的插入的文档会覆盖老的文档。
所以,oplog表使用capped collection是合理的,因为不可能无限制的增长oplog。MongoDB在初始化副本集的时候都会有一个默认的oplog大小:
在64位的Linux,Solaris,FreeBSD以及Windows系统上,MongoDB会分配磁盘剩余空间的5%作为oplog的大小,如果这部分小于1GB则分配1GB的空间
在64的OS X系统上会分配183MB
在32位的系统上则只分配48MB
oplog的大小设置是值得考虑的一个问题,如果oplog size过大,会浪费存储空间;如果oplog size过小,老的oplog记录很快就会被覆盖,那么宕机的节点就很容易出现无法同步数据的现象。
比如,基于上面的例子,我们停掉一个备份节点(port=33333),然后通过主节点插入以下记录,然后查看oplog,发现以前的oplog已经被覆盖了。
通过MongoDB shell连接上这个节点,会发现这个节点一直处于RECOVERING状态。
解决方法:
数据同步
在副本集中,有两种数据同步方式:
initial sync(初始化):这个过程发生在当副本集中创建一个新的数据库或其中某个节点刚从宕机中恢复,或者向副本集中添加新的成员的时候,默认的,副本集中的节点会从离它最近的节点复制oplog来同步数据,这个最近的节点可以是primary也可以是拥有最新oplog副本的secondary节点。
该操作一般会重新初始化备份节点,开销较大
replication(复制):在初始化后这个操作会一直持续的进行着,以保持各个secondary节点之间的数据同步。
initial sync
当遇到上面例子中无法同步的问题时,只能使用以下两种方式进行initial sync了
- 第一种方式就是停止该节点,然后删除目录中的文件,重新启动该节点。这样,这个节点就会执行initial sync
- 注意:通过这种方式,sync的时间是根据数据量大小的,如果数据量过大,sync时间就会很长
- 同时会有很多网络传输,可能会影响其他节点的工作
- 第二种方式,停止该节点,然后删除目录中的文件,找一个比较新的节点,然后把该节点目录中的文件拷贝到要sync的节点目录中
通过上面两种方式中的一种,都可以重新恢复"port=33333"的节点。改变一直处于RECOVERING状态的错误。
6:oplog数据结构
下面来分析一下oplog中字段的含义,通过下面的命令取出一条oplog:
db.oplog.rs.find().skip(1).limit(1).toArray()
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时才有该属性
ts:操作的时间戳,由一个 64 位整数表示,高 32 位是时间戳,低 32 位是增量计数器。
h:操作的唯一标识符,由一个 64 位整数表示,用于保证操作的唯一性。
op:操作类型,有 “i”(插入)、“u”(更新)、“d”(删除)和 “c”(命令)等四种类型。
ns:操作的命名空间,表示操作所属的数据库和集合。
o:操作的具体内容,根据操作类型的不同而不同。
查看oplog的信息
通过"db.printReplicationInfo()"命令可以查看oplog的信息
字段说明:
- configured oplog size: oplog文件大小
- log length start to end: oplog日志的启用时间段
- oplog first event time: 第一个事务日志的产生时间
- oplog last event time: 最后一个事务日志的产生时间
- now: 现在的时间
查看slave状态
通过"db.printSlaveReplicationInfo()"可以查看slave的同步状态
副本节点中执行db.printSlaveReplicationInfo()命令可以查看同步状态信息
source——从库的IP及端口
syncedTo——当前的同步情况,延迟了多久等信息
Oplog 的应用场景
Oplog 提供了一种实时追踪 MongoDB 数据库操作的方法,被广泛应用于以下场景:
1. 数据复制
MongoDB 支持主从复制,通过读取主节点的 Oplog,从节点可以实时复制主节点上的数据变更。从而实现数据的备份和故障恢复。
2. 实时监控
通过读取 Oplog 可以实时监控数据库的更改操作,例如记录用户的登录、注销和数据的增删改等操作。这对于日志记录、审计和安全监控等场景非常有用。
3. 数据同步
Oplog 可以用于多个数据库之间的数据同步,例如将数据从一个 MongoDB 实例复制到另一个 MongoDB 实例。
Oplog 的查询方法
通过查询 Oplog,可以获取数据库操作的详细信息。以下是一些常用的 Oplog 查询方法:
1. 获取最新的操作记录
const oplog = db.getSiblingDB('local').oplog.rs;
// 查询最新的操作记录
const latestOplog = oplog.find().sort({ $natural: -1 }).limit(1);
printjson(latestOplog[0]);
2. 获取指定时间范围的操作记录
const oplog = db.getSiblingDB('local').oplog.rs;
// 指定起始时间和结束时间
const startTimestamp = Timestamp(1625078400, 0);
const endTimestamp = Timestamp(1625164800, 0);
// 查询指定时间范围内的操作记录
const oplogRange = oplog.find({ ts: { $gte: startTimestamp, $lte: endTimestamp } });
oplogRange.forEach((op) => {
printjson(op);
});
3. 获取指定命名空间的操作记录
const oplog = db.getSiblingDB('local').oplog.rs;
// 指定命名空间
const namespace = 'testDB.testCollection';
// 查询指定命名空间的操作记录
const oplogNamespace = oplog.find({ ns: namespace });
oplogNamespace.forEach((op) => {
printjson(op);
});
Oplog 的注意事项
使用 Oplog 需要注意以下几点:
Oplog 中的操作记录是 MongoDB 内部使用的,对于普通应用开发来说,一般不直接操作 Oplog 集合。
Oplog 只记录数据库操作的更改,不记录查询操作。
Oplog 中的操作记录量较大,可以通过设置 Oplog 大小和采样频率等参数来控制。
结语
MongoDB Oplog 是一个重要的特性,提供了实时追踪数据库操作的能力。通过读取 Oplog,我们