修改mongodb oplog size

本文介绍了两种修改MongoDB Oplog大小的方法,一种通过维护模式重新创建Oplog,另一种则是完全停止复制集并重新配置。文章详细展示了每一步操作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

修改mongodb oplog size

oplog简介:

oplog:operations log的简写,存储在一个特殊的数据库中(local),oplog就存储在其中的oplog.$main集合里面,这个集合是一个固定集合,新操作会自动替换旧的操作,以保证oplog不会超过预设的大小,其中的每个文档都代表主节点上执行的一个操作,oplog会包含所有对数据有修改的的操作(查询操作不会记录),默认下,oplog大小会占用64位的实例5%的可用磁盘空间。
mongo复制的过程:主节点应用业务操作修改到数据库中,然后记录这些操作到oplog中,从节点复制这些oplog,然后应用这些修改。ps:这些操作是异步的。如果从节点的操作已经被主节点落下很远,oplog日志在从节点还没执行完,oplog可能已经轮滚一圈了,从节点跟不上同步,复制就会停下,从节点需要重新做完整的同步,为了避免此种情况,尽量保证主节点的oplog足够大,能够存放相当长时间的操作记录。

查询oplog的大小及保存的操作记录持续的时长

repltest:PRIMARY> db.printReplicationInfo()
configured oplog size:   1024MB
log length start to end: 3705secs (1.03hrs)
oplog first event time:  Thu Oct 10 2013 11:13:29 GMT+0800 (CST)
oplog last event time:   Thu Oct 10 2013 12:15:14 GMT+0800 (CST)
now:                     Fri Oct 11 2013 16:33:42 GMT+0800 (CST)

查询从节点的数据源列表,其中有数据滞后的时间

repltest:PRIMARY> db.printSlaveReplicationInfo()
source:   192.168.1.101:37017
syncedTo: Fri Oct 11 2013 16:38:16 GMT+0800 (CST)
= 1 secs ago (0hrs)
source:   192.168.1.100:37017
no replication info, yet.  State: ARBITER
so,修改oplog的大小:(下面介绍两种方式)

方式一:

The oplog exists internally as a capped collection, so you cannot modify its size in the course of normal operations.另:改变oplog大小,需要在每个节点上执行维护模式。(官方推荐)
步骤:

1:重启一个实例以单机模式,

通常再关闭server之前,使用rs.stepDown() 强制primary成为secondary

2:重新创建一个新大小,

其中包含旧的oplgo的入口条目的oplog

3:重启mongod作为replica set的成员

操作步骤:
1>: Restart a Secondary in Standalone Mode on a Different Port
关闭mongod实例:
repset:PRIMARY> use admin
repset:PRIMARY> db.shutdownServer()
重启mongod实例以单机模式,修改端口,并不要加--replSet参数
#vim /etc/mongo.conf
  dbpath=/var/lib/mongodb
  logpath=/var/log/mongodb/mongo.log
  pidfilepath=/var/run/mongo.pid
  directoryperdb=true
  logappend=true
  #replSet=repset
  bind_ip=192.168.1.100,127.0.0.1
  port=37017
  oplogSize=2000
  fork=true# mongod -f /etc/mongo.conf
备份oplog# mongodump --db local --collection 'oplog.rs' --port 37017
2>: Recreate the Oplog with a New Size and a Seed Entry
保存oplog的最新的时间点
> use local
> db.temp.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )
> db.temp.find()
删除旧的oplog
> db.oplog.rs.drop()
3> :Create a New Oplog
创建一个新的Oplog,大小为2G
> db.runCommand( { create: "oplog.rs", capped: true, size: (2 * 1024 * 1024 * 1024) } )
插入前面保存的旧的oplog的时间点的记录
> db.oplog.rs.save( db.temp.findOne() )
> db.oplog.rs.find()
4>:Restart the Member:
关闭单机实例:
> use admin
> db.shutdownServer()
修改回配置# vim /etc/mongo.conf
  dbpath=/var/lib/mongodb
  logpath=/var/log/mongodb/mongo.log
  pidfilepath=/var/run/mongo.pid
  directoryperdb=true
  logappend=true
  replSet=repset
  bind_ip=192.168.1.100,127.0.0.1
  port=37017
  oplogSize=2000
  fork=true
启动mongod
# mongod -f /etc/mongo.conf
重复上述步骤到所有需要更改的节点。

方式二:

步骤:
1:停掉所有replca set节点.
2:主节点删除local库下的文件,从节点删除数据目录下所有文件.
3:修改所有节点配置文件.
4:重启所有节点.
5:重新配置replca set,从节点会重新同步所有数据(initial sync).
ps:此法好处是简单,但需要停掉服务,且如果数据量很大,初始同步的成本较高

1>:关闭mongod实例(所有节点)

> use admin
> db.shutdownServer()

2>:删除local数据库下的所有文件(PRIMARY节点)

# rm -rf /var/lib/mongodb/local/*
  删除mongo数据目录(其他节点上操作,可不要删错哦,建议所有rm操作先mv,待无问题时候再删除)# rm -rf /var/lib/mongodb/*

3> 修改所有节点配置文件(oplogsize)

# vim /etc/mongo.conf
  dbpath=/var/lib/mongodb
  logpath=/var/log/mongodb/mongo.log
  pidfilepath=/var/run/mongo.pid
  directoryperdb=true
  logappend=true
  replSet=repset
  bind_ip=192.168.1.100,127.0.0.1
  port=37017
  oplogSize=2000
  fork=true

4> 重启所有节点mongod

> mongod -f /etc/mongo.conf
<think>我们正在处理一个关于MongoDB Change Stream的错误:NonResumableChangeStreamError。这个错误通常发生在Change Stream无法恢复时,可能是因为底层的事件超出了保留期限或者发生了某些不可恢复的操作。下面我将详细解释原因并提供解决方案。 ## 错误原因 1. **操作日志(oplog)保留期不足**:Change Stream依赖于MongoDB的操作日志(oplog)来获取数据变更。如果Change Stream需要读取的事件已经被oplog覆盖(即超过了oplog的保留期限),那么Change Stream将无法恢复,从而抛出此错误[^1]。 2. **集合删除或重命名**:如果在Change Stream监听期间,目标集合被删除或重命名,那么Change Stream将无法继续,因为原来的集合已经不存在了[^2]。 3. **数据库删除**:如果整个数据库被删除,那么该数据库中的所有Change Stream都会失效[^2]。 4. **分片集群中的分片删除**:在分片集群环境中,如果某个分片被移除,那么依赖于该分片的Change Stream可能会失败[^3]。 5. **无效的恢复令牌**:如果尝试使用一个无效的恢复令牌(resume token)来恢复Change Stream,也会导致此错误。这通常发生在令牌过期或者与当前集群状态不匹配时[^4]。 ## 解决方案 ### 1. 增加oplog大小 确保oplog足够大以覆盖Change Stream可能需要的恢复时间。可以通过以下步骤调整oplog大小: ```javascript // 切换到local数据库 use local // 查看当前oplog大小 db.oplog.rs.stats().maxSize // 调整oplog大小(单位:MB) db.adminCommand({replSetResizeOplog: 1, size: 20000}) ``` ### 2. 避免删除集合或数据库 - 确保在Change Stream运行期间不要删除或重命名被监听的集合。 - 如果必须删除,需要重新创建Change Stream。 ### 3. 处理分片集群变更 在分片集群中,避免在Change Stream运行时移除分片。如果必须移除,需要重新建立Change Stream。 ### 4. 使用可靠的恢复机制 - 定期存储恢复令牌(resume token),但注意令牌可能会过期。建议在每次事件处理时更新存储的令牌。 - 如果遇到此错误,最好的做法是重新创建一个新的Change Stream,并从当前时间点开始监听,而不是尝试恢复。 ### 5. 代码示例:重新创建Change Stream 当捕获到`NonResumableChangeStreamError`时,重新创建Change Stream: ```javascript const { MongoClient } = require('mongodb'); async function runChangeStream() { const client = new MongoClient('mongodb://localhost:27017'); await client.connect(); const db = client.db('test'); const collection = db.collection('items'); let changeStream; try { changeStream = collection.watch(); changeStream.on('change', (change) => { console.log('Change:', change); // 在这里更新存储的恢复令牌(如果需要) }); changeStream.on('error', async (error) => { if (error.name === 'NonResumableChangeStreamError') { console.log('Non-resumable error, restarting change stream...'); // 关闭当前流 await changeStream.close(); // 重新创建Change Stream runChangeStream(); } }); } catch (error) { console.error('Error setting up change stream:', error); } } runChangeStream(); ``` ### 6. 使用`startAfter`选项 如果你保存了最新的有效恢复令牌,可以尝试使用`startAfter`选项来恢复Change Stream: ```javascript const lastResumeToken = ...; // 从持久化存储中获取 collection.watch([], { startAfter: lastResumeToken }); ``` ## 总结 `NonResumableChangeStreamError`通常是由于底层事件不可用或环境发生不可逆变更导致的。最有效的解决方案是重新创建Change Stream。同时,确保oplog大小足够,避免在监听期间删除集合或数据库。 [^1]: MongoDB oplog必须足够大以支持Change Stream的恢复。 [^2]: 集合或数据库的删除会导致Change Stream无法继续。 [^3]: 分片集群的拓扑变化可能影响Change Stream。 [^4]: 使用过期的恢复令牌会导致此错误。 §§相关问题§§ 1. 如何监控MongoDBoplog使用情况? 2. Change Stream在分片集群中的工作原理是什么? 3. 除了`NonResumableChangeStreamError`,Change Stream还有哪些常见错误?</think>### MongoDB NonResumableChangeStreamError 错误解析 #### **错误原因** 1. **操作日志(oplog)过期** Change Stream 依赖 MongoDBoplog 实现数据变更追踪。若 oplog 保留时间过短(默认仅 72 小时),当 Change Stream 恢复时所需的事件可能已被覆盖,触发此错误[^1]。 2. **无效的恢复令牌(resume token)** 恢复令牌过期或与当前集群状态不匹配(如分片迁移、副本集拓扑变更),导致无法从断点恢复[^2]。 3. **集合/数据库删除** 若监听的集合或数据库被删除,Change Stream 将永久失效。 4. **分片集群变更** 在分片集群中,分片删除或集合分片键修改会导致恢复令牌失效。 5. **MongoDB 版本兼容性问题** 低版本 MongoDB(<4.0)或驱动程序版本与服务器不兼容时可能触发此错误。 --- #### **解决方案** ##### 1. **调整 oplog 大小** - 通过以下命令增加 oplog 保留时间(单位:MB): ```javascript // 查看当前 oplog 大小 use local db.oplog.rs.stats().maxSize // 调整 oplog 大小(示例设为 50GB) db.adminCommand({replSetResizeOplog: 1, size: 50000}) ``` - 需确保磁盘空间充足,避免 oplog 被覆盖。 ##### 2. **优化恢复令牌管理** - **存储最新令牌**:每次处理变更事件后更新存储的恢复令牌: ```javascript changeStream.on('change', event => { saveResumeToken(event._id); // 持久化存储令牌 }); ``` - **启动时指定令牌**: ```javascript const lastToken = loadResumeToken(); // 加载存储的令牌 const pipeline = [{ $match: { operationType: 'insert' } }]; const options = { startAfter: lastToken }; const changeStream = collection.watch(pipeline, options); ``` ##### 3. **错误处理与重连** ```javascript changeStream.on('error', async err => { if (err.name === 'NonResumableChangeStreamError') { await changeStream.close(); // 获取新的恢复起点(如当前时间) const newStartPoint = new Date(); restartChangeStream(newStartPoint); } }); ``` ##### 4. **规避高风险操作** - 避免在 Change Stream 运行时删除集合或数据库。 - 分片集群中谨慎执行分片删除或分片键修改。 ##### 5. **升级与兼容性检查** - 确保 MongoDB 服务器 ≥ 4.0。 - 使用最新版官方驱动程序(如 Node.js 的 `mongodb` 驱动 ≥ 4.0)。 --- #### **预防措施** - **监控 oplog 状态**:定期检查 `local.oplog.rs` 的使用率。 - **设置心跳机制**:定期发送空事务维持 Change Stream 活跃。 - **使用 `startAtOperationTime`**:从特定时间点恢复,避免令牌失效: ```javascript const changeStream = collection.watch([], { startAtOperationTime: new Timestamp() }); ``` > **关键提示**:此错误通常表示 **无法从断点恢复**,最佳实践是捕获错误后创建新的 Change Stream 并记录新的恢复起点[^3]。 [^1]: oplog 是 Change Stream 的核心依赖,过小会导致事件丢失。 [^2]: 恢复令牌基于集群拓扑生成,拓扑变更会使其失效。 [^3]: MongoDB 官方建议将 NonResumable 错误视为不可恢复状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值