MongoDB oplog解析

1. oplog 的位置

oplog 存储在 local 数据库下的 oplog.rs 集合中:

local.oplog.rs

2. oplog 的结构

oplog 中的每一条记录都是一个 BSON 文档,主要字段如下:

字段含义示例
ts时间戳(Timestamp)Timestamp(1719999999, 1)
h哈希值(Hash),用于唯一标识操作1234567890123456789
op操作类型(Operation type)“i”(插入), “u”(更新), “d”(删除), “c”(命令)
ns命名空间(Namespace),即数据库.集合“test.users”
o操作内容(Object),具体执行的数据{name: “Alice”}
o2更新操作的查询条件(仅更新时有){_id: ObjectId(…)}

示例文档:

插入操作:

{
  "ts": Timestamp(1719999999, 1),
  "h": NumberLong("1234567890123456789"),
  "op": "i",
  "ns": "test.users",
  "o": {"_id": ObjectId("..."), "name": "Alice"}
}

更新操作:

{
  "ts": Timestamp(1719999999, 2),
  "h": NumberLong("1234567890123456790"),
  "op": "u",
  "ns": "test.users",
  "o2": {"_id": ObjectId("...")},
  "o": {"$set": {"name": "Bob"}}
}

删除操作:

{
  "ts": Timestamp(1719999999, 3),
  "h": NumberLong("1234567890123456791"),
  "op": "d",
  "ns": "test.users",
  "o": {"_id": ObjectId("...")}
}

3. oplog 的作用

  • 数据同步:副本集成员通过 oplog 复制主节点上的写操作,实现数据同步。
  • 增量备份与恢复:可以用 oplog 实现增量数据备份和恢复。
  • 实时数据订阅:部分第三方工具(如 mongo-connectorDebezium)通过解析 oplog 实现数据同步到其他系统(如 Elasticsearch、Kafka)。

4. 如何解析 oplog

可以直接在主节点上查询 local.oplog.rs 集合:

db.getSiblingDB('local').getCollection('oplog.rs').find().limit(10).pretty()

也可以用 Python、Node.js 等驱动读取和解析 oplog:

Python 示例(pymongo)

from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')
oplog = client.local['oplog.rs']

for doc in oplog.find().limit(10):
    print(doc)

5. 常见注意事项

  • oplog 只在副本集模式下存在,单节点没有 oplog。
  • oplog 是循环集合(capped collection),空间有限,旧数据会被覆盖。
  • oplog 只记录写操作,不记录读操作。

6. 相关应用场景

  • 数据同步/订阅(如实时同步到 ES、Kafka)
  • 数据恢复(可根据 oplog 回放操作)
  • 审计与变更追踪

7. oplog 的高级解析技巧

7.1 按时间戳筛选 oplog

oplog 的 ts 字段是一个特殊的时间戳(Timestamp 类型),可以用来筛选一段时间内的操作。例如,获取最近 1 小时的操作:

const oneHourAgo = new Timestamp(Math.floor(Date.now() / 1000) - 3600, 1);
db.getSiblingDB('local').oplog.rs.find({ ts: { $gte: oneHourAgo } })

7.2 按命名空间筛选

如果你只关心某个集合的操作:

db.getSiblingDB('local').oplog.rs.find({ ns: 'test.users' })

7.3 按操作类型筛选

只看插入操作:

db.getSiblingDB('local').oplog.rs.find({ op: 'i' })

只看更新操作:

db.getSiblingDB('local').oplog.rs.find({ op: 'u' })

8. 用 oplog 实现数据同步或增量备份

8.1 实时同步思路

  1. 记录当前的最新 ts(时间戳)。
  2. 定期或实时拉取 ts 大于上次记录的 oplog。
  3. 按 oplog 的操作内容同步到目标系统(如另一个 MongoDB、Elasticsearch、Kafka)。

8.2 Python 实时监听 oplog 示例

利用 find(cursor_type=CursorType.TAILABLE_AWAIT) 实现“尾部监听”:

from pymongo import MongoClient
from pymongo.cursor import CursorType

client = MongoClient('mongodb://localhost:27017/')
oplog = client.local['oplog.rs']

# 获取最新时间戳
latest_ts = oplog.find().sort('$natural', -1).limit(1)[0]['ts']

# 启动 tailable cursor
cursor = oplog.find({'ts': {'$gt': latest_ts}}, cursor_type=CursorType.TAILABLE_AWAIT)

while cursor.alive:
    for doc in cursor:
        # 处理每一条 oplog
        print(doc)
    # 如果没有新数据,稍微休息一下
    time.sleep(1)

这种方式可用于制作“增量同步”、“实时订阅”等功能。


9. 解析 oplog 的常见问题和注意事项

  • oplog 是循环集合,数据不是永久保存
    如果同步进程挂了很久,可能会丢失一部分 oplog,导致数据不一致。需要监控同步进程,及时处理异常。
  • oplog 只记录写操作
    不包含查询、聚合等读操作。
  • oplog 格式会因 MongoDB 版本略有变化
    某些命令(如 dropDatabaserenameCollection)会以 op: 'c' 的形式记录,内容在 o 字段。

10. 实践案例:解析 oplog 生成变更日志

假如你要做一个“变更审计”,可以定期拉取 oplog,然后将每条操作转换为业务日志:

def parse_oplog(doc):
    op_type = doc['op']
    ns = doc['ns']
    ts = doc['ts'].as_datetime()
    if op_type == 'i':
        return f"[{ts}] 插入 {ns}: {doc['o']}"
    elif op_type == 'u':
        return f"[{ts}] 更新 {ns}: 条件 {doc['o2']} 更新内容 {doc['o']}"
    elif op_type == 'd':
        return f"[{ts}] 删除 {ns}: {doc['o']}"
    elif op_type == 'c':
        return f"[{ts}] 命令 {ns}: {doc['o']}"
    else:
        return f"[{ts}] 未知操作 {op_type}"

# 示例
for doc in oplog.find({'ts': {'$gte': some_start_ts}}):
    print(parse_oplog(doc))

11. 相关工具推荐

  • mongo-connector:可将 MongoDB 数据实时同步到 Elasticsearch、Solr、Kafka 等。
  • Debezium MongoDB Connector:企业级 CDC(Change Data Capture)工具,支持 Kafka、MySQL、PostgreSQL 等源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猩火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值