とりあえずAWSで動かしているとして、スナップショットによるバックアップをしている場合に復旧する手順メモ。
LVMによるスナップショットバックアップなどでも、それほど手順は変わらないはずです。
何か操作ミスが行われた前提とします。
リストアする前に行う作業
当然ながらmongoに対してこれ以上アクセスがないようにします。
mongoを一旦停止して、直接DBを別ポートで起動してしまうのが一番安全です。
マスタに最新のoplogがあるはずなので、マスタのみで行います。
mongod --dbpath /path/to/db --port 37017
リストアにはoplogで差分を埋めることになるので、スナップショットした時間以降のすべてのoplogがあることが前提となります。そのため、必ずスナップショットの間隔がoplogに保存される時間を超えないように監視を必要とします。
- oplog監視スクリプト例(
-A oplog
)
oplogはデータサイズ固定で古いものから消えていく設定になっているので、普段は1日分取っているけどバッチ処理で一気に流れてしまうということがあり得るので注意が必要です。スナップショットの間隔を狭めるなりoplogのサイズを大きくしておくといいです。
- oplogサイズ変更手順
復旧したいoplogを調べる
mongoのシェルでuse local
してからdb.oplog.rs.find()
以降にクエリをつけて差分として取り込む対象を絞っておきます。
oplogにはindexが貼られていないので、対象が多いと調べるのが難しいでしょう。直近の操作ならtsに加えて.sort( {$natural : -1} )
をつけて条件を絞ると早かったりします。
oplogをダンプする
下記でダンプできますが、
mongodump --port 37017 -d local -c oplog.rs -o oplogD
この時--query '{ "ts" { $gt: Timestamp(1458790000, 1) } , "ts": { $ne: Timestamp(1458799147, 48) } }'
のように条件が付けることが可能です。よって、ここで操作ミスを取り除いたoplogを作成できます。操作ミスが後のクエリに影響を与えるような処理だったら、操作ミス以降のをデータをすべてダンプしないようにしましょう。
ダンプを取った時間よりちょっと前をtsで指定するとダンプ時間の短縮になります。
そのため、スナップショットを取る際に、タグに最新のoplogのタイムスタンプを入れるようにしておくと便利です。最低でも、システムの最新のタイムスタンプは入れておくべきでしょう。
oplogからの差分リストアを行う場合、リストアしようとしているmongoの最新のoplogのタイムスタンプ以前のものは実行をスキップするという処理になるため、余分にoplogを取ってしまってもも問題ありません。。
もしoplogをすべて削除してからリストアによるoplogの差分復旧を行ったら、すべてのoplogが実行されます。
oplogをリストアできるようにしておく
ダンプしたファイルは./oplogD/local/oplog.rs.bson
に吐き出されるので、適当な別ディレクトリを作ってファイル名をoplog.bsonにします。これは単純にmongorestoreの仕様です。
mkdir oplogR
mv oplogD/local/oplog.rs.bson oplogR/oplog.bson
mongoをスナップショットから復旧する
データベース用のEBSとして別領域に分けてある場合には
- mongodを終了
- mongo用の領域をumount
- AWSコンソールから、ボリュームをdetach
- AWSコンソールから、スナップショットからボリュームを作ってattach
- mongo用の領域をmount
のような手順を踏めばボリュームを交換できます。
oplogから差分を取り込む
oplogのリストア時にレプリケーションが行われているとoplogの実行されないという仕様への対処と、通常のアクセスが来ないように別ポートで
mongod --dbpath /path/to/db --port 37017
で直接mongoを起動します。
この時起動するユーザで新規ファイルは書き込まれてしまうので、復旧後にファイルの権限を戻すようにする必要があります。
起動したら、mongorestore実行してoplogから差分を取り込みます。
この時--oplogLimit <timestamp>
で実行するoplogを制限できますが、指定時間以降のものは全く実行しないだけです。よって、mongodumpの時にqueryで処理してあげた方がやりやすいはずです。
mongorestore --port 37017 --oplogReplay oplogD
レプリカでも同様にします。replSetを使わずに起動しているのでoplogのリストアの結果はoplogには記録されません。
レプリケーションを再開する
接続するホスト名など変わっていなければ、元の設定から起動するだけで復旧するはずです。レプリケーションのホストの情報などもmongoはデータベースに持っているためです。