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-connector、Debezium)通过解析 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 实时同步思路
- 记录当前的最新
ts(时间戳)。 - 定期或实时拉取
ts大于上次记录的 oplog。 - 按 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 版本略有变化
某些命令(如dropDatabase、renameCollection)会以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 等源。
1407

被折叠的 条评论
为什么被折叠?



