AWS上に実践的なMongoDBのレプリケーション構成を構築する手順をまとめます。 前回MongoDBインストール後に作成したAMIから、異なるAvailability ZoneにEC2を作成します。 ホスト名(mongo1、mongo2)を定義して、なるべくec2-userで操作します。 今回はReplicationの設定が中心です。Shardingの設定は別の機会に…。 OS: amazon-linux-ami/2014.03 (64-bit) MongoDB: 2.6.4
■システム構成概要図と方針
mongo1サーバ(10.54.10.90) → port=30001:Primary(初期)
mongo2サーバ(10.54.30.152) → port=30002:Secondary(初期)、port=30003:Arbiter
ReplicaSet Name: psa ←名前は適当です。 Primary/Secondary/Arbiterの頭文字。
MongoDBを利用するアプリの都合ではりますが、フェイルオーバー時の差分更新を考慮して、Priorityは設定せず、PrimaryとSecondaryは随時入れ替わることを想定してディレクトリ構成はできるだけ同一とします。 まず、MongoDBをインストールしたAMIを作成し、先にSecondary/Arbiter側から設定します。次にPrimary側でreplication設定すると作業の流れがスムーズです。
******* Secondary/Arbiter *******
前回作成したAMIからmongo2サーバを作成。mongo1サーバとは別のAZを利用する。replication設定は後ほどPrimaryを想定しているmongo1サーバで実施するため、Secondary/Arbiterの設定を先に進める。
■EC2概要
Instance: i-bb41xxx2 (mongo2)
Private IP: 10.54.30.152
Availability zone: ap-northeast-1c
OS: amazon-linux-ami/2014.03 (64-bit)
■ホスト名変更
[ec2-user@ip-10-54-30-152 ~]$ sudo cp -p /etc/sysconfig/network /etc/sysconfig/network.org [ec2-user@ip-10-54-30-152 ~]$ sudo vi /etc/sysconfig/network [ec2-user@ip-10-54-30-152 ~]$ diff /etc/sysconfig/network /etc/sysconfig/network.org 2c2 < HOSTNAME=mongo2 --- > HOSTNAME=localhost.localdomain [ec2-user@ip-10-54-30-152 ~]$ sudo reboot
■hostsファイルの設定
[ec2-user@mongo2 ~]$ sudo vi /etc/hosts [ec2-user@mongo2 ~]$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain 10.54.10.90 mongo1 10.54.30.152 mongo2 [ec2-user@mongo2 ~]$
■設定ファイル作成(初期SecondaryおよびArbiter)
※Arbiterは固定だが、Primary/Secondaryは入れ替わることを想定しているので、secondary.confのようなファイル名にはしない。
[ec2-user@mongo2 ~]$ vi /data/mongo_rs/conf/mongod.conf [ec2-user@mongo2 ~]$ cat /data/mongo_rs/conf/mongod.conf bind_ip=mongo2 port=30002 dbpath=/data/mongo_rs/db pidfilepath=/var/run/mongodb/mongod.pid logpath=/var/log/mongodb/mongod.log logappend=true fork=true replSet=psa [ec2-user@mongo2 ~]$ mkdir /data/mongo_rs/arb [ec2-user@mongo2 ~]$ vi /data/mongo_rs/conf/arbiter.conf [ec2-user@mongo2 ~]$ cat /data/mongo_rs/conf/arbiter.conf bind_ip=mongo2 port=30003 dbpath=/data/mongo_rs/arb pidfilepath=/var/run/mongodb/arbiter.pid logpath=/var/log/mongodb/arbiter.log logappend=true fork=true replSet=psa [ec2-user@mongo2 ~]$
◆参考:ファイルディスクリプタ数上限値拡張
デフォルトの1024→2048に変更。
[ec2-user@mongo2 ~]$ ulimit -a | grep open; ulimit -n 2048; ulimit -a | grep open open files (-n) 1024 open files (-n) 2048 [ec2-user@mongo2 ~]$システムの規模に応じて上限値を拡張する。
MongoDBのオフィシャルサイトでは"64000"を推奨しているようですが、EC2インスタンスがしょぼいので今回は2048に設定してみます。
この値はログインしているシェルで保持されているため、恒久的な設定でないことに注意!
■mongod起動
## Secondary
[ec2-user@mongo2 ~]$ ulimit -n 2048; sudo mongod --config /data/mongo_rs/conf/mongod.conf about to fork child process, waiting until server is ready for connections. forked process: 1732 child process started successfully, parent exiting [ec2-user@mongo2 ~]$※ec2-userをmongodグループに所属させたり、pidファイルやlogファイルの権限を変えてみたが、ec2-userで起動すると失敗する。
mongodはrootで起動することを想定している??
## Arbiter
[ec2-user@mongo2 ~]$ ulimit -n 2048; sudo mongod --config /data/mongo_rs/conf/arbiter.conf about to fork child process, waiting until server is ready for connections. forked process: 17768 child process started successfully, parent exiting [ec2-user@mongo2 ~]$
## 起動確認
[ec2-user@mongo2 ~]$ /etc/init.d/mongod status mongod (pid 17768 1732) is running... [ec2-user@mongo2 ~]$ ps aux | head -1; ps aux | grep mongod USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1732 0.1 3.1 725500 32024 ? Sl 15:27 0:00 mongod --config /data/mongo_rs/conf/mongod.conf root 17768 0.1 3.1 717308 32076 ? Sl 15:32 0:00 mongod --config /data/mongo_rs/conf/arbiter.conf ec2-user 17862 0.0 0.0 110280 840 pts/0 S+ 15:36 0:00 grep mongod [ec2-user@mongo2 ~]$
## 停止させる場合
mongod stopコマンドだとSecondary/Arbiterのどちらかしか停止できない。
完全に停止させるにはkillコマンドを使用する。
■データベース接続確認
[ec2-user@mongo2 ~]$ mongo mongo2:30002 MongoDB shell version: 2.6.4 connecting to: mongo2:30002/test Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ Questions? Try the support group http://groups.google.com/group/mongodb-user > show dbs admin (empty) local 0.078GB > exit bye [ec2-user@mongo2 ~]$ mongo mongo2:30003 MongoDB shell version: 2.6.4 connecting to: mongo2:30003/test > show dbs admin (empty) local 0.078GB > exit bye [ec2-user@mongo2 ~]$Secondary/Arbiterの準備はこれで完了です。次はPrimaryの設定になります。
◆参考:MongoDBインスタンスの設定値の確認
[ec2-user@mongo2 ~]$ cat /proc/1732/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7772 7772 processes Max open files 2048 2048 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7772 7772 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us [ec2-user@mongo2 ~]$※1732はSecondaryのPIDです。
◆参考:MongoDBモニタリングツール
[ec2-user@mongo2 ~]$ mongostat -h mongo2 --port 30002 connected to: mongo2:30002 insert query update delete getmore command flushes mapped vsize res faults locked db idx miss % qr|qw ar|aw netIn netOut conn repl time *0 1 *0 *0 0 1|0 0 80m 709m 31m 0 local:0.0% 0 0|0 0|0 62b 3k 1 REC 15:41:44 *0 1 *0 *0 0 1|0 0 80m 709m 31m 0 local:0.0% 0 0|0 0|0 62b 3k 1 REC 15:41:45 *0 1 *0 *0 0 1|0 0 80m 709m 31m 0 local:0.0% 0 0|0 0|0 62b 3k 1 REC 15:41:46 *0 1 *0 *0 0 1|0 0 80m 709m 31m 0 local:0.0% 0 0|0 0|0 62b 3k 1 REC 15:41:47 *0 1 *0 *0 0 1|0 0 80m 709m 31m 0 local:0.0% 0 0|0 0|0 62b 3k 1 REC 15:41:48 ^C [ec2-user@mongo2 ~]$
******* Primary *******
■EC2概要Instance: i-eca4xxx5 (mongo1)
Private IP: 10.54.10.90
Availability zone: ap-northeast-1a
OS: amazon-linux-ami/2014.03 (64-bit)
■ホスト名変更
[ec2-user@ip-10-54-10-90 ~]$ sudo cp -p /etc/sysconfig/network /etc/sysconfig/network.org [ec2-user@ip-10-54-10-90 ~]$ sudo vi /etc/sysconfig/network [ec2-user@ip-10-54-10-90 ~]$ diff /etc/sysconfig/network /etc/sysconfig/network.org 2c2 < HOSTNAME=mongo1 --- > HOSTNAME=localhost.localdomain [ec2-user@ip-10-54-10-90 ~]$ sudo reboot
■hostsファイルの設定
[ec2-user@mongo1 ~]$ sudo vi /etc/hosts [ec2-user@mongo1 ~]$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain 10.54.10.90 mongo1 10.54.30.152 mongo2 [ec2-user@mongo1 ~]$※AWSの場合、SecurityGroupでmongo2サーバとの通信を許可しておいてください。
■設定ファイル作成(初期Primary)
[ec2-user@mongo1 ~]$ vi /data/mongo_rs/conf/mongod.conf [ec2-user@mongo1 ~]$ cat /data/mongo_rs/conf/mongod.conf bind_ip=mongo1 port=30001 dbpath=/data/mongo_rs/db pidfilepath=/var/run/mongodb/mongod.pid logpath=/var/log/mongodb/mongod.log logappend=true fork=true replSet=psa [ec2-user@mongo1 ~]$
■mongod起動
[ec2-user@mongo1 ~]$ ulimit -n 2048; sudo mongod --config /data/mongo_rs/conf/mongod.conf about to fork child process, waiting until server is ready for connections. forked process: 1615 child process started successfully, parent exiting [ec2-user@mongo1 ~]$この時点ではまだreplicationされていませんのでご注意を。
■replication設定
いよいよrepricationの設定です。rs.initiate()実行後にコマンドプロンプトが
"ReplicaSet名:PRIMARY>"に変更されます。
## ReplicaSetの初期化
[ec2-user@mongo1 ~]$ mongo mongo1:30001 MongoDB shell version: 2.6.4 connecting to: mongo1:30001/test > rs.initiate() { "info2" : "no configuration explicitly specified -- making one", "me" : "mongo1:30001", "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 } > psa:PRIMARY> rs.conf() { "_id" : "psa", "version" : 1, "members" : [ { "_id" : 0, "host" : "mongo1:30001" } ] } psa:PRIMARY>
## SecandaryとArbiter追加
psa:PRIMARY> rs.add("mongo2:30002") { "ok" : 1 } psa:PRIMARY> rs.addArb("mongo2:30003") { "ok" : 1 } psa:PRIMARY>
## 設定の確認
psa:PRIMARY> rs.conf() { "_id" : "psa", "version" : 3, "members" : [ { "_id" : 0, "host" : "mongo1:30001" }, { "_id" : 1, "host" : "mongo2:30002" }, { "_id" : 2, "host" : "mongo2:30003", "arbiterOnly" : true } ] } psa:PRIMARY> rs.status() { "set" : "psa", "date" : ISODate("2014-09-04T07:13:39Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "mongo1:30001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 461, "optime" : Timestamp(1409814782, 1), "optimeDate" : ISODate("2014-09-04T07:13:02Z"), "electionTime" : Timestamp(1409814552, 2), "electionDate" : ISODate("2014-09-04T07:09:12Z"), "self" : true }, { "_id" : 1, "name" : "mongo2:30002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 53, "optime" : Timestamp(1409814782, 1), "optimeDate" : ISODate("2014-09-04T07:13:02Z"), "lastHeartbeat" : ISODate("2014-09-04T07:13:38Z"), "lastHeartbeatRecv" : ISODate("2014-09-04T07:13:38Z"), "pingMs" : 2, "syncingTo" : "mongo1:30001" }, { "_id" : 2, "name" : "mongo2:30003", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 37, "lastHeartbeat" : ISODate("2014-09-04T07:13:38Z"), "lastHeartbeatRecv" : ISODate("2014-09-04T07:13:39Z"), "pingMs" : 2 } ], "ok" : 1 } psa:PRIMARY>
## 念のためSecondary側でも確認
[ec2-user@mongo1 ~]$ mongo mongo2:30002 MongoDB shell version: 2.6.4 connecting to: mongo2:30002/test psa:SECONDARY> rs.conf() { "_id" : "psa", "version" : 3, "members" : [ { "_id" : 0, "host" : "mongo1:30001" }, { "_id" : 1, "host" : "mongo2:30002" }, { "_id" : 2, "host" : "mongo2:30003", "arbiterOnly" : true } ] } psa:SECONDARY>
◆参考:replicationの動作検証
Primaryで作成した1000件のレコードが、Secondaryにレプリケートされいているか確認。
## レコード作成(Primary)
[ec2-user@mongo1 ~]$ mongo mongo1:30001/reptest MongoDB shell version: 2.6.4 connecting to: mongo1:30001/reptest psa:PRIMARY> for(var i=0; i<1000; i++) db.repcoll.insert( { "uid":i, "value":Math.floor(Math.random()*1000+1) } ) WriteResult({ "nInserted" : 1 }) psa:PRIMARY> db.repcoll.count() 1000 psa:PRIMARY> db.repcoll.find() { "_id" : ObjectId("5408144a85529d4cbf6eb107"), "uid" : 0, "value" : 929 } { "_id" : ObjectId("5408144a85529d4cbf6eb108"), "uid" : 1, "value" : 547 } { "_id" : ObjectId("5408144a85529d4cbf6eb109"), "uid" : 2, "value" : 26 } { "_id" : ObjectId("5408144a85529d4cbf6eb10a"), "uid" : 3, "value" : 813 } { "_id" : ObjectId("5408144a85529d4cbf6eb10b"), "uid" : 4, "value" : 609 } { "_id" : ObjectId("5408144a85529d4cbf6eb10c"), "uid" : 5, "value" : 992 } { "_id" : ObjectId("5408144a85529d4cbf6eb10d"), "uid" : 6, "value" : 75 } { "_id" : ObjectId("5408144a85529d4cbf6eb10e"), "uid" : 7, "value" : 449 } { "_id" : ObjectId("5408144a85529d4cbf6eb10f"), "uid" : 8, "value" : 817 } { "_id" : ObjectId("5408144a85529d4cbf6eb110"), "uid" : 9, "value" : 422 } { "_id" : ObjectId("5408144a85529d4cbf6eb111"), "uid" : 10, "value" : 133 } { "_id" : ObjectId("5408144a85529d4cbf6eb112"), "uid" : 11, "value" : 280 } { "_id" : ObjectId("5408144a85529d4cbf6eb113"), "uid" : 12, "value" : 613 } { "_id" : ObjectId("5408144a85529d4cbf6eb114"), "uid" : 13, "value" : 830 } { "_id" : ObjectId("5408144a85529d4cbf6eb115"), "uid" : 14, "value" : 790 } { "_id" : ObjectId("5408144a85529d4cbf6eb116"), "uid" : 15, "value" : 155 } { "_id" : ObjectId("5408144a85529d4cbf6eb117"), "uid" : 16, "value" : 915 } { "_id" : ObjectId("5408144a85529d4cbf6eb118"), "uid" : 17, "value" : 317 } { "_id" : ObjectId("5408144a85529d4cbf6eb119"), "uid" : 18, "value" : 903 } { "_id" : ObjectId("5408144a85529d4cbf6eb11a"), "uid" : 19, "value" : 89 } Type "it" for more psa:PRIMARY>
## 確認(Secondary)
[ec2-user@mongo1 ~]$ mongo mongo2:30002/reptest MongoDB shell version: 2.6.4 connecting to: mongo2:30002/reptest psa:SECONDARY> db.repcoll.count() 2014-09-04T16:30:49.898+0900 count failed: { "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" } at src/mongo/shell/query.js:191 psa:SECONDARY>→読み取り許可設定が必要。
psa:SECONDARY> db.getMongo().setSlaveOk() psa:SECONDARY> db.repcoll.count() 1000 psa:SECONDARY> db.repcoll.find() { "_id" : ObjectId("5408144a85529d4cbf6eb107"), "uid" : 0, "value" : 929 } { "_id" : ObjectId("5408144a85529d4cbf6eb108"), "uid" : 1, "value" : 547 } { "_id" : ObjectId("5408144a85529d4cbf6eb109"), "uid" : 2, "value" : 26 } { "_id" : ObjectId("5408144a85529d4cbf6eb10a"), "uid" : 3, "value" : 813 } { "_id" : ObjectId("5408144a85529d4cbf6eb10b"), "uid" : 4, "value" : 609 } { "_id" : ObjectId("5408144a85529d4cbf6eb10c"), "uid" : 5, "value" : 992 } { "_id" : ObjectId("5408144a85529d4cbf6eb10d"), "uid" : 6, "value" : 75 } { "_id" : ObjectId("5408144a85529d4cbf6eb10e"), "uid" : 7, "value" : 449 } { "_id" : ObjectId("5408144a85529d4cbf6eb10f"), "uid" : 8, "value" : 817 } { "_id" : ObjectId("5408144a85529d4cbf6eb110"), "uid" : 9, "value" : 422 } { "_id" : ObjectId("5408144a85529d4cbf6eb111"), "uid" : 10, "value" : 133 } { "_id" : ObjectId("5408144a85529d4cbf6eb112"), "uid" : 11, "value" : 280 } { "_id" : ObjectId("5408144a85529d4cbf6eb113"), "uid" : 12, "value" : 613 } { "_id" : ObjectId("5408144a85529d4cbf6eb114"), "uid" : 13, "value" : 830 } { "_id" : ObjectId("5408144a85529d4cbf6eb115"), "uid" : 14, "value" : 790 } { "_id" : ObjectId("5408144a85529d4cbf6eb116"), "uid" : 15, "value" : 155 } { "_id" : ObjectId("5408144a85529d4cbf6eb117"), "uid" : 16, "value" : 915 } { "_id" : ObjectId("5408144a85529d4cbf6eb118"), "uid" : 17, "value" : 317 } { "_id" : ObjectId("5408144a85529d4cbf6eb119"), "uid" : 18, "value" : 903 } { "_id" : ObjectId("5408144a85529d4cbf6eb11a"), "uid" : 19, "value" : 89 } Type "it" for more psa:SECONDARY>Primaryに登録されたデータがSecondaryにレプリケートされていることを確認できました。
◆参考:MongoDBフェイルオーバー検証
Primaryに障害が発生した場合、SecandaryがPrimaryに昇格するか確認してみます。
## mongo1サーバのPrimary停止前(Arbiterに接続して確認)
[ec2-user@mongo1 ~]$ mongo mongo2:30003 --eval "printjson(rs.status())" | egrep "name|stateStr" "name" : "mongo1:30001", "stateStr" : "PRIMARY", "name" : "mongo2:30002", "stateStr" : "SECONDARY", "name" : "mongo2:30003", "stateStr" : "ARBITER", [ec2-user@mongo1 ~]$mongo ホスト名:ポート番号 --eval "printjson(mongoシェル)" とすると、Bashから直接mongoシェルを実行できます。
## mongo1サーバのPrimary停止
[ec2-user@mongo1 ~]$ ps -ef | grep mongo root 1615 1 1 16:05 ? 00:02:43 mongod --config /data/mongo_rs/conf/mongod.conf ec2-user 3681 2574 0 19:04 pts/0 00:00:00 grep mongo [ec2-user@mongo1 ~]$ sudo kill -9 1615 [ec2-user@mongo1 ~]$ [ec2-user@mongo1 ~]$ mongo mongo2:30003 --eval "printjson(rs.status())" | egrep "name|stateStr" "name" : "mongo1:30001", "stateStr" : "(not reachable/healthy)", "name" : "mongo2:30002", "stateStr" : "PRIMARY", "name" : "mongo2:30003", "stateStr" : "ARBITER", [ec2-user@mongo1 ~]$SecandaryがPrimaryに昇格しました!!
※この後、元Primaryを復旧させると優先順位を定義していないのでSecondaryとなります。
長文にお付き合いいただきありがとうございました。こちらの情報が何かのお役に立てましたら幸いです。
0 件のコメント:
コメントを投稿