MongoDBでReplicaSetにメンバーを追加/削除する方法と、その注意点
MongoDBで、ReplicaSetにメンバーを追加/削除する方法は、Adding a New Set Memberにある通りです。
rs.add("node1:27018");
で追加したり、
rs.remove("node1:27018");
で削除したり。
追加する際は
- 既存データを物理的にコピーしてきて戻す方法
- カラの状態から同期を取る方法
があります。
1000万件程度であれば、1.でも数分で終わる模様。数億件以上ある場合は、2.で戻した方が作業が早いかもしれません。
注意点1
その際に気をつける点は、local.*のファイルはコピーしてこないこと。local以外のコレクションに対応するファイルだけコピーしてきて、あとは起動後にrs.add()すればOKです。local.*がいると、データの整合が取れなくなって「still initiating」って状態で止まってしまいます。これやっちゃってハマりました・・・orz
ちなみに、その場合でも一度サーバを止めてlocal.*ファイルを全部削除して起動し直せばOKみたいです。
注意点2
あともう一つ注意する点は、メンバーのvotesの数の合計が偶数にならないこと。MongoDB sharding and replication with (only) 3 servers - Part 2: One Replica-Setに以下のように説明されています。
The members of a set will elect their master just as well as we do with our politicians. The master has to get more than half of the available votes. Problem: Imagine a set with four members. What happens if two vote for node A to get master and the two others vote for node B?
Neither A nor B will get master, because no node got more than half of the available votes.
Therefore the number of votes in a replica set has to be odd-numbered. You can reach this by easily add one more node as a new slave to the set - simultaneously increasing database availability. But if you don't have the resources for an additional node, there are two other possibilities:1. Add an arbiter, which is a mongod process and a member of the set, but only exists to solve majority problems (http://www.mongodb.org/display/DOCS/Adding+an+Arbiter)
2. Change the number of votes the members have, so the number is unequal.
PRIMARYになるためには、全体のvotes数の過半数より多い票を獲得しなければならないため、votes数が偶数になってしまうと、残りのvotes数が半数になった時点でPRIMARYがいなくなってしまいます。例えば、
ノード名 | votes |
---|---|
node1 | 1 |
node2 | 1 |
node3 | 1 |
node4 | 1 |
となると、上記のうち2台が死んだ時点でvotesの数が過半数の2となってしまい、PRIMARYがいなくなってしまいます。PRIMARYがいなくなるということは、ReplicaSetの構成変更も出来なくなるので、死んだ2台のうちいずれかを起動するまでは何も出来ません。
ノード名 | votes |
---|---|
node1 | 2 |
node2 | 1 |
node3 | 1 |
node4 | 1 |
であれば、仮にnode3/node4が死んでも、残りのvotes数は3なので、node1/node2のいずれかはPRIMARYでいられます(node1が死んでしまうと、あと1台しか死ぬことは出来ませんが)。この辺はArbiterで調整したり。
自分は、
ノード名 | votes |
---|---|
node1 | 1 |
node2 | 1 |
node3 | 1 |
に対して
ノード名 | votes |
---|---|
node1 | 1 |
node2 | 1 |
node3 | 1 |
node4 | 1 |
node5 | 1 |
node6 | 1 |
と新たに3つのノードを追加したところ、追加した3つが前述した理由で起動できない状態となっていたため、既存ノードからPRIMARYがいなくなってしまいました。
ノード名 | votes | State |
---|---|---|
node1 | 1 | SECONDARY |
node2 | 1 | SECONDARY |
node3 | 1 | SECONDARY |
node4 | 1 | still initiating |
node5 | 1 | still initiating |
node6 | 1 | still initiating |
追加した3つのノードを起動することも出来ず、PRIMARYがいないのでrs.remove()でノードを消すこともできず、完全に詰んだ状態に・・・orz
local.*を消せばよかったみたいですが、このときには気付かなかったので、node1/node2/node3を取得していたバックアップから復元して対応しました。