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