ローカル環境でMongoDBのReplicationを構成する方法
こんにちは。RGA(リアルグローブ・オートメーティッド)でインフラエンジニアをしている張です。
少し前、学習のためローカル環境にMongoDBを3つ起動してレプリケーションをセットアップしてみようと試みました。インターネット上に同じようなセットアップに関連する情報は多々存在しているものの、実際に手を動かしてみて、少し異なるところがあったので、自分がやりやすい方法をまとめてみます。
構築に使用した環境は以下の通りです。
1. データファイルを格納するためのフォルダを作成
まずは、データファイル格納用フォルダ用に data フォルダーを作成し、さらにその配下に3つインスタンス用のデータファイル格納用フォルダ(db1, db2, db3)を作成します。
mkdir -p db{1,2,3}
2. 設定ファイル(mongod.conf)を作成
続いて、設定ファイルを作成します。MongoDBの設定ファイル(mongod.conf)のオプションについては、MongoDBの公式ドキュメントを参照。
db1, db2, db3はそれぞれに対して作成する必要があります。
ディレクトリ構成
ディレクトリ構成は以下のようになります。
|data
|--db1
| |--mongod.conf
|--db2
| |--mongod.conf
|--db3
| |--mongod.conf
ポート番号
ポートは下記で設定しました。
db1: 28017
db2: 28018
db3: 28019
設定ファイルの内容
db1用のmongod.confは下の内容で設定しています。
systemLog:
destination: file
path: {usr}/data/db1/mongod.log
logAppend: true
storage:
dbPath: {usr}/data/db1
net:
bindIp: 0.0.0.0
port: 28017 # ポート番号
replication:
replSetName: rs0 # レプリカセット名:rs0
processManagement:
fork: true
db2, db3 は上記の設定を各自のフォルダにコピーして、path、dbPath、portをそれぞれ修正します。
3. 設定ファイルを適用
下記のコマンドで設定ファイルを適用します。
mongod -f {DBディレクトリ名}/mongod.conf
例えばdb1のmongod.confを適用する場合は以下のようになります。
mongod -f db1/mongod.conf
設定ファイルの適用が正しくできた場合、下記のようなメッセージが表示されますので、確認してください。
about to fork child process, waiting until server is ready for connections.
forked process: 87472
child process started successfully, parent exiting
db2, db3 も同様に適用します。
適用してから、稼働状況をさらに確認したい場合、psコマンドを実行するのが手っ取り早いですね。
ps -ef | grep mongod
4. インスタンスに接続
設定ファイルが適用できたら、下記のコマンドで db1 にアクセスします。
mongod --port 28017 --quiet
※ --quietは、接続情報を簡潔に表示されるオプション
1) rs.initiate()でレプリカセットのメンバーを追加
rs.initiate()は、新しいレプリカセットの設定した時に初期化を行うメソッドです。便利のため、rs.initiate()でセットするとき、db1, db2, db3のホスト情報をmembersという設定フィールドに追加しておきます。
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:28017"},{_id: 1, host: "localhost:28018"},{_id: 2,host:"localhost:28019"}]})
上記のコマンド叩いた結果は下のようになります。
{ "ok" : 1 }
上のスクショでは、下のように表示されています。
rs0:SECONDARY>
もう一回Enterを押すと、下のように切り替わります。
rs0:PRIMARY>
ここまでで、すでに"rs0"というレプリカセットのメンバー(db1)にアクセスできたことになります。
※PRIMARYやSECONDARYは何ものかは、こちらのページ「Replica Set Members」を参照。
簡単に説明すると、デフォルトの設定ではDBが初期化された時に SECONDARYと認められます。上記の説明から、現在のレプリカセットは、PRIMARY(1つ)、SECONDARY(2つ)があると明らかになります。
次の動作を検証するため、もう一回Enterを押すと、db1をPRIMARYに変更します。
この時点では、db1がPRIMARYとして設定されていて、まだログインしていないdb2, db3はSECONDARYになています。次のステップで、各メンバーのstateStrで確認できます。もちろん、db1 が一時的に止まってしまった場合、db2, db3のどれかがPRIMARYに変更されます。
2) メンバーの追加状況を確認
こちらのコマンドでステータスを確認します。
rs.status()
上図で、db1 のstateStrが”PRIMARY”になっているのがわかります。
5. レプリカセットの稼働状況を確認
db1 が "PRIMARY"である限り、書き込みと読み込みができるので、db1 にデータを挿入してみて、db2 側から様子を確認してみます。
なお、本ブログでは"Arbiter"というメンバーをスキップしていますので、時間があればこちらのドキュメントをチェックしてみてください→"Arbiter"について
メンバー db2 にアクセスする
mongo localhost:28018 --quiet
上記のコマンドでdb2 にアクセスしてから、db1の内容が見れるのかを、下記のコマンドで試します。
db.test.find()
しかし、下のようなエラーメッセージが表示されました。
"errmsg" : "not master and slaveOk=false",
このメッセージは、まだ db1 の slave になってないよ、db1は知らない人、という意味ですので、両方の関係を築き上げましょう。
最初は、rs.slaveOk()で試してみます。ただし、このメソッドは次のリリースで削除されるそうなので、推奨のrs.secondaryOk()を使うのが良いでしょう。
db.test.find()
で もう一回確認してみると、問題が解決していることがわかります。ただし、下のスクショのように、testというDBにはデータがないから、何も表示されません。
データ同期確認
では、メンバー db1 にデータを追加して、db2 から同期さるか確認して見ましょう。
まず、db1に適当なデータをinsertします。
db.test.insert({a:0})
insert直後にdb2 側で確認してみます。
期待通りdb1 で insert した{a: 0}が db2 側で見れました!
ローカル環境だから、すぐに反映されたと感じましが、レプリカセットのメンバーが遠距離であっても、数十ミリ秒程度の遅延しか掛からないと言われています。
db1 を kill してから db2 が昇格
次に、psで db1 のプロセス番号を確認し、kill してみましょう。
今回は auxを使ってみます。 ※ef派とaux派がこれからもpeace&loveで暮らしていくように。余談→あなたはPS -EF派なのか、AUXF派なのかをちょっとだけまとめてみた
ps aux | grep mongod
db1のプロセスコードは87472がわかった。
kill 87472
しばらく待ってから、db1 が稼働していないことが確認できる。
db2がPRIMARYに昇格されることも確認できる。
おまけ - db1を再起動したら、どうなるのか?
先ほどkillしたdb1を再起動したら、db1またPRIMARYに昇格されるか、それともそのままSECONDARYとして起動するでしょうか?
どうやら、db2がPRIMARYとして稼働している限り、db1はSECONDARYとして動作するようです。
以上MongoDBのレプリケーションをセットアップする方法でした。
――――――――――――――――――――――――――――――――――
【ご案内】
ITシステム開発やITインフラ運用の効率化、高速化、品質向上、その他、情シス部門の働き方改革など、IT自動化導入がもたらすメリットは様々ございます。
IT業務の自動化にご興味・ご関心ございましたら、まずは一度、IT自動化の専門家リアルグローブ・オートメーティッド(RGA)にご相談ください!
お問合せは以下の窓口までお願いいたします。
【お問い合わせ窓口】
代表窓口:info@rg-automated.jp
URL: https://rg-automated.jp