MongoDBのバックアップ周りを実際にやってみる

2年ぶりにMongoDBを触ることになったので、リハビリがてらReplica SetとSharding周りを触ってます。
とりあえず今日はReplica Setとバックアップ周り。
なぜバックアップまわりかというと、前に触ってた時は本当に基礎部分しかやってなかったので、バックアップ方法などはあまりチェックしてなかったためです。

日付が一番新しかったのが CyberAgentにおけるMongoDB のスライドだったので、この方法でやってみようかなと。(はてなダイアリーってslide shareって埋め込みできなかったのね)
arbiterとnovoteにしている理由がはっきりしなかったのですが、わざわざTwitterで回答を頂きました。ありがとうございました。


ということで実際にやってみます。

Replica Setをくむ

ReplicaSetで遊ぶ - 個人的なまとめ で Replica Setを組む方法はすでに知ってるのですが、MongoDB 2.6.6になってから色々変わっていると思ったので、再度ドキュメントを見なおしてみました。
そしたらconfigファイルのフォーマットがYAMLになっててびっくり。でも、これってなんか意味があるんだろうかと謎。まぁ、設定が構造として表現できるから楽になるのかな?ぐらい。

サーバ構成としては、3台サーバを用意して、その中の1台にarbiter用のmongodを設定しました。設定ファイルは下記にまとめてます。
最初にmongodを立ち上げた後に、arbiterを立ち上げて、rsコマンドでarbiterを追加するところまでは順調に行ったので、これで試せる状態になりました。
バックアップ対象のmongodを落としたあとに、他のprimaryやsecondaryを落とした時にもちゃんとサービスが継続できるかというのが確認ポイントです。
早速やってみる。

初期状態(rs.status()の一部抜粋)

id 状態 備考
1 SECONDARY
2 SECONDARY バックアップ対象のサーバ
3 PRIMARY
4 ARBITER

_id2のmongodを落とす

id 状態 備考
1 SECONDARY
2 (not reachable/healthy) バックアップ対象のサーバ
3 PRIMARY
4 ARBITER

ここで_id:1のsecondaryのプロセスを落とす

id 状態 備考
1 (not reachable/healthy)
2 (not reachable/healthy) バックアップ対象のサーバ
3 SECONDARY
4 ARBITER

あれ?全部secondaryになった ( ゚д゚)ポカーン
あ、novoteの設定入れてない。vote(投票権)の全体数の過半数の票を取らないといけないのに、全体の半数になったからだ orz
rs.reconfigで設定します。(reconfigを実行するとrs.stepDownが走るので気をつけましょう)

rs:SECONDARY> rs.config()
{
	"_id" : "rs",
	"members" : [
		{ "_id" : 1, },
		{ "_id" : 2, "votes" : 0 },
		{ "_id" : 3, },
		{ "_id" : 4, "arbiterOnly" : true }
	]
}
rs:SECONDARY> rs.status();
{
	"members" : [
		{ "_id" : 1, "health" : 1, "state" : 2, "stateStr" : "SECONDARY", },
		{ "_id" : 2, "health" : 1, "state" : 1, "stateStr" : "PRIMARY", },
		{ "_id" : 3, "health" : 1, "state" : 2, "stateStr" : "SECONDARY", },
		{ "_id" : 4, "health" : 1, "state" : 7, "stateStr" : "ARBITER", }
	],
}

再度、バックアップ対象サーバのmongodを落とそうと思ったのですが、stepDownが走った時に該当サーバがprimaryになってるじゃありませんか。
ということで、バックアップ対象サーバのpriorityを0にして、primaryにならないようにしました。
最初はprimaryにしない設定をした時に悪影響出るかなと思ったのですが、どちらにしてもバックアップ対象以外で2つ落ちたら、クラスタがダウンするので、こちらのほうがシンプルかなと思いました。(あえてmongodも冗長化するのであれば、novotesかつpriorityが0ではないsecondaryを追加するとかぐらいですかね...未検証ですが)
ちなみに2.6からvoteの値は1より大きい値を設定すると警告がでます。[http://docs.mongodb.org/manual/reference/replica-configuration/#local.system.replset.members[n].votes]

rs:PRIMARY> rs.config()
{
	"members" : [
		{ "_id" : 1, },
		{ "_id" : 2, "votes" : 0, "priority" : 0 },
		{ "_id" : 3, },
		{ "_id" : 4, "arbiterOnly" : true
		}
	]
}

最終的にはこういう状態でバックアップスタート

id 状態 備考
1 SECONDARY
2 SECONDARY バックアップ対象のサーバ votes:0(投票権がない), priority:0(primaryにならない)
3 PRIMARY
4 ARBITER

バックアップ対象サーバのmongodを落とす

id 状態 備考
1 SECONDARY
2 (not reachable/healthy) バックアップ対象のサーバ votes:0(投票権がない), priority:0(primaryにならない)
3 PRIMARY
4 ARBITER

id:1(secondary)のmongodを落とす

id 状態 備考
1 (not reachable/healthy)
2 (not reachable/healthy) バックアップ対象のサーバ votes:0(投票権がない), priority:0(primaryにならない)
3 PRIMARY
4 ARBITER

id:1のmongodを立ち上げた後、id:3(primary)のmongodを落とす

id 状態 備考
1 PRIMARY
2 (not reachable/healthy) バックアップ対象のサーバ votes:0(投票権がない), priority:0(primaryにならない)
3 (not reachable/healthy)
4 ARBITER

id:3のmongodを立ち上げた後、id4(arbiter)を落とす

id 状態 備考
1 SECONDARY
2 (not reachable/healthy) バックアップ対象のサーバ votes:0(投票権がない), priority:0(primaryにならない)
3 PRIMARY
4 (not reachable/healthy)

とりあえず、バックアップの設定はできた。本当はMMS: The easiest way to run MongoDB | Cloud managed MongoDB on the infrastructure of your choiceとか使うほうがいいんだろうけどなー

設定ファイル

mongod.conf

systemLog:
  destination: file
  path: "/var/log/mongodb/mongodb_s1.log"
  logAppend: true
storage:
 journal:
   enabled: true
 smallFiles: true
 dbPath: "/data/db/s1"
processManagement:
 fork: true
net:
 port: 27017
replication:
 oplogSizeMB: 10
 replSetName: rs

arbiter.conf

systemLog:
  destination: file
  path: "/var/log/mongodb/arbiter.log"
  logAppend: true
storage:
 journal:
   enabled: false
 smallFiles: true
 dbPath: "/data/arb"
processManagement:
 fork: true
net:
 port: 30000
replication:
 oplogSizeMB: 10
 replSetName: rs