MongoDBのバックアップ周りを実際にやってみる
2年ぶりにMongoDBを触ることになったので、リハビリがてらReplica SetとSharding周りを触ってます。
とりあえず今日はReplica Setとバックアップ周り。
なぜバックアップまわりかというと、前に触ってた時は本当に基礎部分しかやってなかったので、バックアップ方法などはあまりチェックしてなかったためです。
日付が一番新しかったのが CyberAgentにおけるMongoDB のスライドだったので、この方法でやってみようかなと。(はてなダイアリーってslide shareって埋め込みできなかったのね)
arbiterとnovoteにしている理由がはっきりしなかったのですが、わざわざTwitterで回答を頂きました。ありがとうございました。
@hachi_eiji これは現状綺麗にクラスタのバックアップを取るのに、同時にmongodのプロセスを落とすのが一番手軽な為です。落としても問題ない様にnovoteにしてます。で、バックアップ中にRSのもう一台が落ちるとクラスタダウンなのでarbiter入れてると言うわけですー
— Akihiro Kuwano (@kuwa_tw) 2014, 12月 30ということで実際にやってみます。
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