change streams 是当前最稳妥的增量同步方案:它封装 oplog 逻辑,自动处理分片、主从切换、断连重试和 resume token 持久化;要求 replica set 或 sharded cluster 部署,不支持单机模式;需正确配置权限(如 local 库 read)、连接参数及 token 持久化时机。

Change Streams 是当前最稳妥的增量同步方案
Python 客户端连接 MongoDB 4.0+ 时,Change Streams 应作为默认选择,它封装了 oplog 读取逻辑,自动处理分片集群、主节点切换、断连重试和 resume token 持久化。oplog 手动解析已不推荐——它要求 replica set 部署、需直连 primary、权限配置复杂,且在 5.0+ 中对非 admin 数据库的 oplog 访问进一步受限。
常见错误现象:OperationFailure: not authorized on local database(没给 clusterMonitor 角色)或 CommandNotSupportedOnView: Cannot run aggregation on 'local.oplog.rs'(误对 view 执行聚合)。
- 必须用
mongod启动的 replica set,单机模式不支持 Change Streams - 连接字符串里不能含
?replicaSet=xxx以外的多余参数,否则可能触发错误的节点发现逻辑 -
watch()返回的游标默认不阻塞,需显式传max_await_time_ms(如1000)避免空轮询
如何正确初始化并持久化 resume token
中断后从上次位置继续,关键不在“存 token”,而在“何时存”。在事件处理完成后再更新 token,否则会丢数据。token 本身是 BSON 对象,不能直接 JSON 序列化,要用 json_util 或转成字符串存。
示例:处理完一条变更后更新本地 checkpoint
from bson import json_util
# ... 处理 change_doc 后
with open("resume_token.json", "w") as f:
json.dump(json_util.dumps(change_stream._resume_token), f)
- 首次启动无 token 时,传
resume_after=None(不是 omit 参数),否则会报TypeError - 不要在循环外提前读
change_stream._resume_token——它只在收到第一个事件后才有效 - 若用 Redis 存 token,注意它的 TTL 设置;若用文件,确保写入后
os.fsync(),避免缓存未落盘
Change Streams 的过滤与性能边界
聚合管道能过滤操作类型、集合名、字段变更,但过度过滤会拖慢整个流——每个变更仍要经 mongod 解析管道。真正影响吞吐的是 full_document 选项:设为 "updateLookup" 会触发额外查询,QPS 显著下降。
- 只监听特定集合:
[{"$match": {"ns.coll": "orders"}}],别用正则匹配ns - 避免
full_document="updateLookup",改用应用层查旧值(如果业务允许) - 大批量 update 场景下,
start_at_operation_time比resume_after更高效,但它只能指定时间点,无法跳过中间某几条
oplog 回退方案仅适用于特殊场景
只有当 MongoDB 版本 local 数据库之外的权限时,才考虑手动读 oplog。此时必须自己处理:ts 时间戳排序、h 全局唯一序号去重、v:2 格式解析、以及 oplog 回滚(o2 字段里的 _id 反向查找)。
典型错误:KeyError: 'o'(误把 cmd 类型当作文档操作)、OverflowError: timestamp out of range(用 datetime.fromtimestamp() 解析 Timestamp 对象)。
- oplog 查询必须带
.sort("$natural", 1),否则顺序错乱 -
find({"ts": {"$gt": last_ts}})不可靠,需配合h字段做二次校验 - oplog 文档的
o和o2结构随操作类型变化极大,insert/update/delete 的字段含义完全不同
真正难的从来不是“怎么读”,而是“怎么确认每条变更都只处理一次且不漏”。token 持久化时机、网络分区下的幂等设计、目标存储的事务边界——这些才是压测时最先暴露的问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











