MongoDB on AWS Cloud その4:Configサーバをレプリカセットに移行する

2016.10.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、菊池です。

MongoDB on AWS 第4弾です。前回アップグレードした環境を使い、MongoDB 3.2 の新機能であるConfigサーバのレプリカセット構成を試します。

過去の記事:

はじめに

作業の前提条件と手順のサマリです。

前提条件

  • Configサーバ、mongosはVer. 3.2.10
  • Configサーバは3台(Config0/1/2)の独立構成で、ストレージエンジンはMMAPv1で稼働

手順サマリ

公式のドキュメントに記載の手順に従って進めます。マニュアルには、サービスを停止して行う手順と、Ver.3.2.4以降でサポートされたオンラインで実施する手順が記載されています。

今回の環境はVer.3.2.10なので、オンラインで可能な手順で実施していきます。

  1. Balancerの停止
  2. Configサーバの1台(Config0)をレプリカセットに変更(シングル)
  3. Configサーバを3台追加起動(Config3/4/5)し、2.のレプリカセットに追加
  4. 2.で最初にレプリカセットに変更したConfigサーバ(Config0)をレプリカセットから削除
  5. mongosの接続先をレプリカセットに変更
  6. 元から稼働していたConfigサーバ(Config0/1/2)を停止
  7. Balancerの再開

要は、既存のConfigサーバを1台と新規のConfigサーバ3台でレプリカセットを作り、mongosをそちらに向けた後に既存のConfigサーバを削除する流れになります。

mongodb-config-convert-to-rep

注意事項

  • レプリカセットに追加するConfig3/4/5は、必ず新規で構築しましょう。既存のConfig1/2をレプリカセットに追加しようとするとmongosが落ちました
  • mongosのログを常に確認し、異常がないか見ながら作業をしてください。

移行手順

1. Balancer停止

まずは事前作業として、シャーディング時にデータチャンクを移動させる働きを持つBalancerを停止します。mongosにログイン(今回の構成ではPrimaryノードで起動)し、sh.getBalancerState()でBalancerの状態確認、sh.stopBalancer()で停止します。

$ mongo
MongoDB shell version: 3.2.10
connecting to: test
mongos> sh.stopBalancer()
Waiting for active hosts...
Waiting for the balancer lock...
Waiting again for active hosts after balancer is off...
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
mongos> sh.getBalancerState()
false
mongos>

 

2. Config0をレプリカセットに変更

Config0にログインし、1台のみのレプリカセットに変更します。まずはrs.initiateでレプリカセットの初期化をします。

$ mongo localhost:27030
MongoDB shell version: 3.2.10
connecting to: localhost:27030/test
configsvr> rs.initiate( {
...    _id: "csReplSet",
...    configsvr: true,
...    version: 1,
...    members: [ { _id: 0, host: "10.0.2.124:27030" } ]
... } )
{ "ok" : 1 }
configsvr>

Config0の設定ファイル/etc/mongod.confを修正し、一度再起動します。

net:
  port: 27030

systemLog:
  destination: file
  logAppend: true
  path: /data/mongod.log

storage:
  dbPath: /data
  journal:
    enabled: true

processManagement:
  fork: true
  pidFilePath: /var/run/mongod/mongod.pid

sharding:
  clusterRole: configsvr
  configsvrMode: sccc     #追記

replication:
  replSetName: csReplSet    #追記
$ sudo service mongod restart
       Stopping mongod:                                           [  OK  ]
       Starting mongod:                                           [  OK  ]

これで再度ログインすると、プロンプトが変化し1台のみのレプリカセットになっています。

$ mongo localhost:27030
MongoDB shell version: 3.2.10
connecting to: localhost:27030/test
csReplSet:PRIMARY> rs.status()
{
       	"set" : "csReplSet",
       	"date" : ISODate("2016-10-07T02:51:13.587Z"),
       	"myState" : 1,
       	"term" : NumberLong(1),
       	"configsvr" : true,
       	"heartbeatIntervalMillis" : NumberLong(2000),
       	"members" : [
       		{
       			"_id" : 0,
       			"name" : "10.0.2.124:27030",
       			"health" : 1,
       			"state" : 1,
       			"stateStr" : "PRIMARY",
       			"uptime" : 22,
       			"optime" : {
       				"ts" : Timestamp(1475808670, 2),
       				"t" : NumberLong(1)
       			},
       			"optimeDate" : ISODate("2016-10-07T02:51:10Z"),
       			"infoMessage" : "could not find member to sync from",
       			"electionTime" : Timestamp(1475808651, 1),
       			"electionDate" : ISODate("2016-10-07T02:50:51Z"),
       			"configVersion" : 1,
       			"self" : true
       		}
       	],
       	"ok" : 1
}
csReplSet:PRIMARY>

 

3. 新規Configサーバを3台追加

次に、各サーバにConfigサーバを追加していきます。既存のConfigサーバが稼働するインスタンス上に追加でサーバを起動するようにします。以下のような設定ファイルを/etc/mongod0.confとして作成しました。

$ cat /etc/mongod0.conf
net:
  port: 27031

systemLog:
  destination: file
  logAppend: true
  path: /data/mongod0.log

storage:
  dbPath: /data/wt
  journal:
    enabled: true

processManagement:
  fork: true
  pidFilePath: /var/run/mongod/mongod0.pid

sharding:
  clusterRole: configsvr

replication:
  replSetName: csReplSet

また、既存の起動スクリプト/etc/init.d/mongodをコピーし、/etc/init.d/mongod0を作成しておきます。

$ sudo cp -p /etc/init.d/mongod /etc/init.d/mongod0

読み込む設定ファイルのみ/etc/mongod0.confに変更しておきましょう。

$ cat /etc/init.d/mongod0 | grep CONFIGFILE
CONFIGFILE="/etc/mongod0.conf"
OPTIONS=" -f $CONFIGFILE"

mongod0を起動します。

$ sudo service mongod0 start
Starting mongod:                                           [  OK  ]

これを3台全てのConfigサーバで実施し、Config3/4/5とします。

再度、Config0に戻り、起動したConfig3/4/5をレプリカセットのメンバーとして追加します。

csReplSet:PRIMARY> rs.add( { host: "10.0.3.43:27031", priority: 0, votes: 0 } )
{ "ok" : 1 }
csReplSet:PRIMARY> rs.add( { host: "10.0.4.81:27031", priority: 0, votes: 0 } )
{ "ok" : 1 }
csReplSet:PRIMARY> rs.add( { host: "10.0.2.124:27031", priority: 0, votes: 0 } )
{ "ok" : 1 }
csReplSet:PRIMARY>

ここで、priority: 0, votes: 0としておくことで、Primaryの選出には参加せず、昇格もしないメンバーとなります。

csReplSet:PRIMARY> rs.status()
{
       	"set" : "csReplSet",
       	"date" : ISODate("2016-10-07T03:40:20.843Z"),
       	"myState" : 1,
       	"term" : NumberLong(1),
       	"configsvr" : true,
       	"heartbeatIntervalMillis" : NumberLong(2000),
       	"members" : [
       		{
       			"_id" : 0,
       			"name" : "10.0.2.124:27030",
       			"health" : 1,
       			"state" : 1,
       			"stateStr" : "PRIMARY",
       			"uptime" : 2969,
       			"optime" : {
       				"ts" : Timestamp(1475811612, 1),
       				"t" : NumberLong(1)
       			},
       			"optimeDate" : ISODate("2016-10-07T03:40:12Z"),
       			"electionTime" : Timestamp(1475808651, 1),
       			"electionDate" : ISODate("2016-10-07T02:50:51Z"),
       			"configVersion" : 6,
       			"self" : true
       		},
       		{
       			"_id" : 1,
       			"health" : 1,
       			"state" : 2,
       			"stateStr" : "SECONDARY",
       			"uptime" : 947,
       			"optime" : {
       				"ts" : Timestamp(1475811612, 1),
       				"t" : NumberLong(1)
       			},
       		 "optimeDate" : ISODate("2016-10-07T03:40:12Z"),
     			 "lastHeartbeat" : ISODate("2016-10-07T03:40:18.943Z"),
       		 "lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.953Z"),
         		"pingMs" : NumberLong(0),
         		"syncingTo" : "10.0.2.124:27030",
         		"configVersion" : 6
       		},
       		{
       			"_id" : 2,
       			"name" : "10.0.4.81:27031",
       			"health" : 1,
       			"state" : 2,
       			"uptime" : 446,
       			"optime" : {
       				"ts" : Timestamp(1475811612, 1),
       				"t" : NumberLong(1)
       			},
       			"optimeDate" : ISODate("2016-10-07T03:40:12Z"),
       			"lastHeartbeat" : ISODate("2016-10-07T03:40:18.949Z"),
       			"lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.968Z"),
       			"pingMs" : NumberLong(2),
       			"syncingTo" : "10.0.3.43:27031",
       			"configVersion" : 6
       		},
       		{
       			"_id" : 3,
       			"name" : "10.0.2.124:27031",
       			"health" : 1,
       			"state" : 2,
       			"stateStr" : "SECONDARY",
       			"uptime" : 7,
       			"optime" : {
       				"ts" : Timestamp(1475811612, 1),
       				"t" : NumberLong(1)
       			},
       			"optimeDate" : ISODate("2016-10-07T03:40:12Z"),
       			"lastHeartbeat" : ISODate("2016-10-07T03:40:18.942Z"),
       			"lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.965Z"),
       			"pingMs" : NumberLong(0),
       			"syncingTo" : "10.0.3.43:27031",
       			"configVersion" : 6
       		}
       	],
       	"ok" : 1
}
csReplSet:PRIMARY>

追加した全てのメンバーが"SECONDARY"となっていればデータの同期も完了です。なお、追加したConfigサーバは全てWiredTigerストレージエンジンでデータを保持しています。

レプリカセットの設定を変更し、全てのメンバーのPriorityとvotesを1とします。

csReplSet:PRIMARY> var cfg = rs.conf();
csReplSet:PRIMARY> cfg.members[0].priority = 1;
1
csReplSet:PRIMARY> cfg.members[1].priority = 1;
1
csReplSet:PRIMARY> cfg.members[2].priority = 1;
1
csReplSet:PRIMARY> cfg.members[3].priority = 1;
1
csReplSet:PRIMARY> cfg.members[0].votes = 1;
1
csReplSet:PRIMARY> cfg.members[1].votes = 1;
1
csReplSet:PRIMARY> cfg.members[2].votes = 1;
1
csReplSet:PRIMARY> cfg.members[3].votes = 1;
1
csReplSet:PRIMARY> rs.reconfig(cfg);
{ "ok" : 1 }
csReplSet:PRIMARY>

 

4. Config0を切り離し

最初にレプリカセットのメンバーとなったConfig0を切り離します。まず、Config0でrs.stepDownによりPrimaryから降格させます。

csReplSet:PRIMARY> rs.stepDown(600)
2016-10-07T03:42:40.457+0000 I NETWORK  [thread1] reconnect localhost:27030 (127.0.0.1) ok
csReplSet:SECONDARY>

次に設定ファイル/etc/mongod.confから、configsvrMode: scccの記述を削除し、再起動します。

net:
  port: 27030

systemLog:
  destination: file
  logAppend: true
  path: /data/mongod.log

storage:
  dbPath: /data
  journal:
    enabled: true

processManagement:
  fork: true
  pidFilePath: /var/run/mongod/mongod.pid

sharding:
  clusterRole: configsvr
  configsvrMode: sccc     # <- 削除

replication:
  replSetName: csReplSet
$ sudo service mongod restart
       Stopping mongod:                                           [  OK  ]
       Starting mongod:                                           [  OK  ]

これでレプリカセットの状態を確認すると、Config0のstateが"stateStr" : "REMOVED"となり、新たに別のConfigサーバがPrimaryに選出されています。

csReplSet:SECONDARY> rs.status()
{
      	"set" : "csReplSet",
      	"date" : ISODate("2016-10-07T03:47:25.537Z"),
      	"myState" : 2,
      	"term" : NumberLong(2),
      	"syncingTo" : "10.0.2.124:27031",
      	"configsvr" : true,
      	"heartbeatIntervalMillis" : NumberLong(2000),
      	"members" : [
      		{
      			"_id" : 0,
      			"name" : "10.0.2.124:27030",
      			"health" : 1,
      			"state" : 10,
      			"stateStr" : "REMOVED",
      			"uptime" : 34,
      			"optime" : {
      				"ts" : Timestamp(1475811769, 1),
      				"t" : NumberLong(2)
      			},
      			"optimeDate" : ISODate("2016-10-07T03:42:49Z"),
      			"lastHeartbeat" : ISODate("2016-10-07T03:47:25.095Z"),
      			"lastHeartbeatRecv" : ISODate("2016-10-07T03:47:24.229Z"),
      			"pingMs" : NumberLong(2),
      			"syncingTo" : "10.0.2.124:27031",
      			"configVersion" : 7
      		},
      		{
      			"_id" : 1,
      			"name" : "10.0.3.43:27031",
      			"health" : 1,
      			"state" : 1,
      			"stateStr" : "PRIMARY",
      			"uptime" : 871,
      			"optime" : {
      				"ts" : Timestamp(1475812042, 3),
      				"t" : NumberLong(2)
      			},
      			"optimeDate" : ISODate("2016-10-07T03:47:22Z"),
      			"lastHeartbeat" : ISODate("2016-10-07T03:47:24.900Z"),
      			"lastHeartbeatRecv" : ISODate("2016-10-07T03:47:24.947Z"),
      			"pingMs" : NumberLong(2),
      			"electionTime" : Timestamp(1475811768, 1),
      			"electionDate" : ISODate("2016-10-07T03:42:48Z"),
      			"configVersion" : 7
      		},
~~~~~~~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~~~~~

 

5. mongosの接続先変更

 

mongosの接続先をレプリカセットに変更します。/etc/mongos.confconfigDB:を、新たに作成したレプリカセットの接続先に書き換えます。

変更前:

net:
 port: 27017

systemLog:
 destination: file
 logAppend: true
 path: /log/mongos.log

processManagement:
 fork: true
 pidFilePath: /var/run/mongod/mongos.pid

sharding:
 configDB: 10.0.3.43:27030,10.0.4.81:27030,10.0.2.124:27030

変更後:

net:
 port: 27017

systemLog:
 destination: file
 logAppend: true
 path: /log/mongos.log

processManagement:
 fork: true
 pidFilePath: /var/run/mongod/mongos.pid

sharding:
 configDB: csReplSet/10.0.3.43:27031,10.0.4.81:27031,10.0.2.124:27031

mongosを再起動

$ sudo service mongos restart
       Stopping mongod:                                           [  OK  ]
       Starting mongod:                                           [  OK  ]

これでレプリカセットへの接続ができました。

6. Config0/1/2を停止

 

元々あったConfigサーバを停止します。まずはConfig0をレプリカセットから完全に削除します。新しいPrimaryにログインし、

csReplSet:PRIMARY> rs.remove("10.0.2.124:27030")
{ "ok" : 1 }
csReplSet:PRIMARY>

これで新規に追加した3台のみのレプリカセットになりました。

csReplSet:PRIMARY> rs.status()
{
      	"set" : "csReplSet",
      	"date" : ISODate("2016-10-07T03:53:10.578Z"),
      	"myState" : 1,
      	"term" : NumberLong(2),
      	"configsvr" : true,
      	"heartbeatIntervalMillis" : NumberLong(2000),
      	"members" : [
      		{
      			"_id" : 1,
      			"name" : "10.0.3.43:27031",
      			"health" : 1,
      			"state" : 1,
      			"stateStr" : "PRIMARY",
      			"uptime" : 1804,
      			"optime" : {
      				"ts" : Timestamp(1475812389, 2),
      				"t" : NumberLong(2)
      			},
      			"optimeDate" : ISODate("2016-10-07T03:53:09Z"),
      			"electionTime" : Timestamp(1475811768, 1),
      			"electionDate" : ISODate("2016-10-07T03:42:48Z"),
      			"configVersion" : 8,
      			"self" : true
      		},
      		{
      			"_id" : 2,
      			"name" : "10.0.4.81:27031",
      			"health" : 1,
      			"state" : 2,
      			"stateStr" : "SECONDARY",
      			"uptime" : 1215,
      			"optime" : {
      				"ts" : Timestamp(1475812382, 1),
      				"t" : NumberLong(2)
      			},
      			"optimeDate" : ISODate("2016-10-07T03:53:02Z"),
      			"lastHeartbeat" : ISODate("2016-10-07T03:53:08.637Z"),
      			"lastHeartbeatRecv" : ISODate("2016-10-07T03:53:08.642Z"),
      			"pingMs" : NumberLong(2),
      			"syncingTo" : "10.0.2.124:27031",
      			"configVersion" : 8
      		},
      		{
      			"_id" : 3,
      			"name" : "10.0.2.124:27031",
      			"health" : 1,
      			"state" : 2,
      			"stateStr" : "SECONDARY",
      			"uptime" : 777,
      			"optime" : {
      				"ts" : Timestamp(1475812382, 1),
      				"t" : NumberLong(2)
      			},
      			"optimeDate" : ISODate("2016-10-07T03:53:02Z"),
      			"lastHeartbeat" : ISODate("2016-10-07T03:53:08.621Z"),
      			"lastHeartbeatRecv" : ISODate("2016-10-07T03:53:08.631Z"),
      			"pingMs" : NumberLong(0),
      			"syncingTo" : "10.0.3.43:27031",
      			"configVersion" : 8
      		}
      	],
      	"ok" : 1
}
csReplSet:PRIMARY>

あとは個別に起動しているmongodを停止していけばOKです。  

7. Balancer再開

 

最後に、停止していたBalancerを再開させます。

mongos> sh.setBalancerState(true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
mongos> sh.getBalancerState()
true
mongos>

以上で全ての手順が完了です。

まとめ

Ver.3.2からサポートされたConfigサーバのレプリカセットへの移行を試しました。WiredTigerへの移行も含め、公式のドキュメントにしっかりと移行の手順が記載されていますので、その通りに実施していけば問題ありません。

AWSの提供するCloudFormationテンプレートで構築したMongoDBクラスタを、最新バージョン・構成へ移行する手順を何回かに分けて紹介してきました。

今後も、MongoDBの新しいバージョンや新機能の追加があれば紹介していきたいと思います。