一、背景

为了调大 oplog window 窗口时间,在调大 oplog 的值后,引发了从库宕机。

日志抓取:

2022-08-30T08:32:40.761+0800 I REPL member to sync from
2022-08-30T08:32:40.761+0800 E REPL catch up -- enter ng maintenance mode
2022-08-30T08:32:40.762+0800 I REPL [replicat on 2) could not find
[rsBackgroundSync) too stale to [rsBackgroundSync) Our newest OpTime : { ts :
mestamp 1503977172000127 , t: 1 }
2022-08-30T08:32:40.762+0800 I REPL [rsBackgroundSync) Earliest OpTime available
is { ts: Timestamp 150399845100011, t: - 1 }
2022-08-30T08:32:40.762+0800 I REPL [rsBackgrou dSync] See http :
//dochub.mongodb.org/core/resyncingaverystalereplicasetmember
2022-08-30T08:32:40.762+0800 I REPL [rsBackgroundSync] going into maintenance
mode th 1820 other mantenance mode tasks in progress
2022-08-30T08:33:19.769+0800 I REPL candidate: 192.168.1.250:28000
2022-08-30T08:33:19.769+0800 I REPL [rsBackgroundSync] sync source
[repl cation 2] We are too stale to use 192.168.1.250:28000 as async
source.Blacklisting thiss source because
our last fetched timestamp: 59a4ded4:lb is before their earliest
timestamp:59a524a9:2le for lmin until: 2022-08-30T08:34:19.769+0800

二、原因

在本案例中存在延迟从库的问题,延迟从库由于延迟,还没有应用到 oplog 就被 "drop"了,进而导致延迟从库处于 recovering 状态。

三、解决方案

(1) 先取消延迟配置,扩容延时从库的 oplog 大小,再扩容主库的 oplog //db.adminCommand({replSetResizeOplog:1,size:1000})

(2) 对于主库需要先降级再进行升级操作。

rs.stepDown()

3.1 修改 oplog 有四种方法

3.1.1 方法一

步骤如下:

(1) 停掉所有 secondary 节点

(2) 主节点删除 local 目录下文件,副本节点删除数据目录下所有文件

(3) 修改所有节点的配置文件,如:oplogSize=1000

(4) 重启所有节点,包括主节点和副本节点

(5) 重新配置 replca set,副本节点会重新同步数据(initial sync)

优点:操作简单。

缺点:需要停服务,若数据量大,数据同步代价高。

3.1.2 方法二

步骤如下:

(1) remove 其中一个 secondary 节点,并关闭 mongod 服务,删除数据目录下所有文件

(2) 修改此节点的参数文件,如:oplogSize=1000,并启动 mongod 服务

(3) 在 primary 节点执行 rs.add()将此节点加入到 replica set

(4) 循环 1-3 步骤,将所有副本节点全部改完

(5) primary 节点执行 rs.stepDown()将主节点降级为副本节点

(6) 从新的主节点 remove 掉此节点,并进行步骤 1-3。这样逐个修改每个节点,完成 oplog 修改。

优点:解决了方法一中的停机问题。

缺点:每个节点都要逐个重新同步,时间代价更高。

3.1.3 方法三

The oplog exists internally as a capped collection, so you cannot modify its size in the course of normal operations.

另:改变 oplog 大小,需要在每个节点上执行维护模式。(官方推荐)

(1) 关闭 mongod

关闭 mongod 实例,如果是 primary 节点,执行 rs.stepDown() 降级

PRIMARY> rs.stepDown()

(2) 修改配置文件

修改配置文件,修改端口,注释掉 replSet 和认证相关的设置

(3) 启动 mongod 实例,并备份 oplog

mongod -f /mongodb/conf/mongodb.conf

mongodump -d local -c oplog.rs --port 27018 -h 172.16.254.134 -o /mongodb/backup

(4) 重建 oplog

保存 oplog 最新时间点

> use local

switched to db local

> db.temp.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )

WriteResult({ "nInserted" : 1 })

> db.temp.find()

{ "_id" : ObjectId("608a914089abaa981f14e888"), "ts" : Timestamp(1619693066, 1), "h" : NumberLong(0) }

#删除旧的 oplog
db.oplog.rs.drop()

#重建新的 oplog,大小为 2GB
> db.runCommand( { create: "oplog.rs", capped: true, size: (2 * 1024 * 1024 * 1024) } )

(5) 插入前面保存的 oplog 时间点记录

> db.oplog.rs.save( db.temp.findOne() )
> db.oplog.rs.find()

(6) 关闭 mongod 实例

> use admin

switched to db admin

> db.shutdownServer()

(7) 最后恢复 mongodb.conf 到初始状态,启动

3.1.4 方法四

如果你的 MongoDB 版本为 4.0 以后的版本,可以直接使用 replSetResizeOplog 修改。

(1) 查看 oplog 大小

SECONDARY> db.getReplicationInfo()

(2) 修改 oplog 大小

SECONDARY> db.adminCommand({replSetResizeOplog:1,size:2000})

(3) 验证 oplog 大小

SECONDARY> db.getReplicationInfo()

(4) 整理碎片,回收空间(可选)

> use local

switched to db local

> db.runCommand({"compact" : "oplog.rs"})