はじめに
MongoDBでReplica Setの構成を組むと、メンバー間でデータの同期が行われます。
同期の仕組みを理解していないと、障害が発生した時の対応を誤ってしまうことがあるので、ここにまとめておきます。
環境
$ mongod --version
db version v4.0.8
同期の仕組み
簡単にまとめると下記の通りです。
- Primaryで書き込みが実行されると、そのオペレーションをlocal.oplog.rsというcollectionに保存する。
- Secondaryは、Primaryからlocal.oplog.rsをコピーする。
- Secondaryは、コピーしたlocal.oplog.rsを順次実行する。
データをコピーしているのではなく、オペレーションをコピーしているというところが味噌です。
oplogの容量制限
oplogはcapped collectionという容量に制限のあるcollectionです。
つまり、長時間のダウンでoplogが保存されている期間を過ぎた場合は、同期が不可能になってしまいます(STALE状態)。
こうなってしまうと、Initial Syncでゼロから同期を始めなければいけなくなります。
oplogのサイズや保存されている期間は下記コマンドで確認できます。
PRIMARY> rs.printReplicationInfo()
configured oplog size: 2574.97265625MB
log length start to end: 11667867secs (3241.07hrs)
oplog first event time: Wed Apr 03 2019 16:54:58 GMT+0900 (JST)
oplog last event time: Fri Aug 16 2019 17:59:25 GMT+0900 (JST)
now: Fri Aug 16 2019 17:59:27 GMT+0900 (JST)
保存期間が短く、長時間ダウンで同期が不可能になってしまう危険性がある場合は、oplogの容量を大きくすることで対応ができます。
下記コマンドでoplogの容量を変更できます(単位はMB)。
PRIMARY> db.adminCommand({ replSetResizeOplog: 1, size: 3000 })
lastStableCheckpointTimestamp (ver.4.0〜)
Replica Set全てが同期された最終時刻のことです。
下記コマンドで確認できます。
PRIMARY> db.adminCommand( { replSetGetStatus : 1 } )
〜
"lastStableCheckpointTimestamp" : Timestamp(1565946285, 1),
〜
Replica SetのメンバーがInitial Sync等で同期していたり、ダウンしていたりすると、この値は長時間更新されません。これは注意が必要です(詳細は下記Recoveryで)。
Recovery ※注意
Replica Setメンバーは、起動時にRecoveryが実行されます。
公式には見当たりませんでしたが、どうやらlastStableCheckpointTimestamp 〜 oplogの最終更新日までのoplogを実行しているようです。
[initandlisten] Recovering from stable timestamp: Timestamp(1565241749, 5) (top of oplog: { ts: Timestamp(1565281045, 1), t: 61 }, appliedThrough: { ts: Timestamp(0, 0), t: -1 }, TruncateAfter: Timestamp(0, 0))
[initandlisten] Starting recovery oplog application at the stable timestamp: Timestamp(1565241749, 5)
[initandlisten] Replaying stored operations from { : Timestamp(1565241749, 5) } (exclusive) to { : Timestamp(1565281045, 1) } (inclusive).
Initial Sync中はlastStableCheckpointTimestampが更新されておらず、その間にレプリカセットのメンバーを再起動すると、Recoveryが走り、Initial Sync開始時刻から現在までのoplogが実行され、完了するまで正常起動しないということが起きます。
データ量の多いDBだとInitial Syncに長時間かかることがあるので、その間に下手に再起動をかけると、oplog実行待ちの間サービスが停止してしまう、なんてことになりかねないので注意が必要です。
また、Secondaryがダウンしている状態で、Primaryを再起動すると、Secondaryがダウンしている期間中のoplogがPrimaryで実行されてしまいます。これも同様に注意が必要です。SecondaryがダウンしたままPrimaryを再起動したい場合は、そのSecondaryをメンバーから外しておくという操作が必要です。