Change Streams 不能跨副本集所有节点监听,仅支持在 primary 节点上基于 oplog 创建;需通过含 replicaSet 参数的连接字符串连接,并确保权限(如 clusterMonitor)与配置匹配,配合 resumeAfter 持久化 token 实现断线续传。

Change Streams 能否跨副本集所有节点监听?
不能。Change Streams 本质是基于 oplog 的聚合管道,只能在单个 mongod 实例(通常是 primary)上建立监听;它不提供“全集群范围”的统一订阅入口,所谓“全集群”必须由应用层协调多个流或路由到 primary 后统一消费。
如何确保 Change Stream 始终连接到 primary?
客户端驱动会自动重连并重新建立 stream,但前提是连接字符串中包含完整的副本集配置和 replicaSet 参数。漏掉这个参数会导致连接降级为 standalone 模式,watch() 直接报错 CommandNotSupportedOnView 或 FailedToSatisfyReadPreference。
- 连接字符串必须形如:
mongodb://node1:27017,node2:27017,node3:27017/?replicaSet=rs0&readPreference=primary - 不要手动指定
host:port单点连接,否则失去自动故障转移能力 - 使用
startAfter或resumeAfter时,token 必须来自同一 replica set 的 oplog 上下文,跨节点 resume 会触发CursorNotFound
监听整个数据库或所有集合是否可行?
MongoDB 6.0 支持数据库级和集群级 Change Streams,但有严格前提:必须连接到 primary,且用户权限需包含 clusterMonitor 角色(集群级)或 dbOwner(数据库级)。常见错误是权限不足导致 Unauthorized 或静默无事件。
- 集群级监听(监听所有数据库变更):
db.watch([], { fullDocument: "updateLookup" })—— 注意第一个参数是空数组,不是{} - 数据库级监听:
db.getSiblingDB("mydb").watch() - 避免在
admin数据库上调用watch(),它不支持 Change Streams
Resumability 和网络中断后如何不丢事件?
Change Streams 默认不具备强持久化恢复能力。断连后若未显式保存 resumeToken,重连时从最新时间点开始,中间变更就丢失了。MongoDB 不保存客户端的 resume 状态,全靠你存、你传、你校验。
- 每次收到变更都应提取并持久化
change._id(即resumeToken),推荐写入本地文件或轻量存储(如 Redis) - 重启后用
resumeAfter: savedToken初始化 stream,而非startAtOperationTime(后者依赖服务器时钟一致性,易偏移) - 注意
resumeToken有生命周期:oplog 截断后旧 token 失效,触发ResumeInProgress错误,此时需降级为全量同步或跳过
实际部署中,最常被忽略的是权限模型与连接模式的耦合——看着连接成功,watch() 却返回空流或报错,八成是角色没赋全,或者连接串里缺了 replicaSet。










