Edited at

mongodbの輪廻転生(スケールイン)

More than 3 years have passed since last update.

俺です。

満を持して準備したmongodbも、時には育たないことがあります。

そんなときはスケールインしなければなりません。

今回は育たなかったmongodbを供養して、小さい形で輪廻転生させる話です。


条件と移行前移行後


  • 移行中はサービス停止を伴う

  • mongodbクラスタのシャードを削除するのではなく、新しく準備する

  • mongodumpで静止点バックアップを取得してmongorestoreでDB単位のリストアを実行する

  • 各mongodbクラスタに作られているデータベース及びコレクションはバッティングしないこと(潰してしまうので)


as is


  • mongodb cluster *2

  • cluster内のロール


    • conf * 3

    • shard * 2


      • replica set *2(member *3)





計 18(9*2)台

各アプリケーションサーバでmongosが起動し、mongos経由でmongodbクラスタを利用しているものとします。


to be


  • mongodb cluster *1

  • cluster内のロール


    • shard * 1

    • replica set *1

    • conf + replica set member *3



計 3台

各アプリケーションサーバでmongosが起動し、mongos経由でmongodbクラスタを利用しているものとします。


移行後モンゴの構築


mongodbをインストール

Amazon Linux 2015.09なら現時点でmongodb 3.0.9-1がインストールされます。

よーしお兄さんWiredTiger使っちゃうぞー

$ sudo yum install mongodb -y


mongodb config(metadata)用定義


  • /etc/mongoc.conf

# mongodb config

systemLog:
destination: file
path: /var/log/mongodb/mongod_config_27019.log
logAppend: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod_config_27019.pid
net:
port: 27019
storage:
dbPath: "/var/lib/mongodb/mongoc"
engine: wiredTiger
wiredTiger:
engineConfig:
journalCompressor: none # default snappy
collectionConfig:
blockCompressor: none # default snappy
sharding:
clusterRole: "configsvr"


  • /etc/init.d/mongoc

mongo configの起動スクリプトを準備します。

yumでインストールしたmongodbのinitスクリプトをコピーして修正します。


  • mongocの起動

$ sudo service mongoc start


mongodb shard(replicaset)用定義

いつかまた大きく育つことを祈り、replSetNameにオリジン00を指定しておきます。


  • /etc/mongod.conf

# mongodb mongod

systemLog:
destination: file
path: /var/log/mongodb/mongod_27017.log
logAppend: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod_27017.pid
net:
port: 27017
storage:
dbPath: "/var/lib/mongodb/mongod"
engine: wiredTiger
wiredTiger:
engineConfig:
journalCompressor: none # default snappy
collectionConfig:
blockCompressor: none # default snappy
replication:
replSetName: "mongodb_replicaset00"
sharding:
clusterRole: "shardsvr"


  • /etc/init.d/mongod

mongodの起動するスクリプトを作成します。

yumでインストールしたmongodbのinitスクリプトをコピーして修正します。


  • mongodの起動

$ sudo service mongod start

以上で新環境のmongo config/mongodが起動しました。


replica setの作成

3台バラバラになっているモンゴのハートを一つにします。


  • Primaryにするmongodbノードで操作

$ mongo --port=27017

mongod> config = { "_id": "mongodb_replicaset00", "members": [ { "_id": 0, "host": '172.16.11.21:27017'}, { "_id": 1, "host": '172.16.11.22:27017'}, { "_id": 2, "host": '172.16.11.23:27017'} ] }
mongod> rs.initiate(config);
PRIMARY


backup用replica set memberの設定

replica set memberは3台あるので、1台をhiddenにしておきます。


  • backup用replica set member

今回は"_id":"1"のmemberをhidden memberにしておきます。

mongodb_replicaset00:PRIMARY> cfg = rs.config()

{
"_id" : "mongodb_replicaset00",
"version" : 2,
"members" : [
{
"_id" : 0,
"host" : "172.16.11.21:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 1,
"host" : "172.16.11.22:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 2,
"host" : "172.16.11.23:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatTimeoutSecs" : 10,
"getLastErrorModes" : {

},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}
}
mongodb_replicaset00:PRIMARY> cfg.members[2].priority = 0
0
mongodb_replicaset00:PRIMARY> cfg.members[2].hidden = true
true
mongodb_replicaset00:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(1455458942, 1),
"electionId" : ObjectId("56c07ea680f80b802b651ba2")
}
}
mongodb_replicaset00:PRIMARY>rs.config()
mongodb_replicaset00:PRIMARY> rs.config()
{
"_id" : "mongodb_replicaset00",
"version" : 2,
"members" : [
{
"_id" : 0,
"host" : "172.16.11.21:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 1,
"host" : "172.16.11.22:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 2,
"host" : "172.16.11.23:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true,
"priority" : 0,
"tags" : {

},
"slaveDelay" : 0,
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatTimeoutSecs" : 10,
"getLastErrorModes" : {

},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}
}


アプリケーションサーバ(mongos)の設定


新クラスタ用mongos定義作成

新しいmongo clusterへの接続定義を作成します。

新しいmongo clusterのmongo configノードのIPはDNS登録しておきます。

(公式ドキュメント上はmongodのノード名もDNSかhostsで名前解決できるようにしておくのが推奨されてたはず..)


  • /etc/mongos.conf

  # mongos(mongodb router)

systemLog:
destination: file
path: /var/log/mongodb/mongos.log
logAppend: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongos.pid
net:
port: 37017
sharding:
configDB: mongodb-conf0.mongo.internal:27019,mongodb-conf1.mongo.internal:27019,mongodb-conf2.mongo.internal:27019


  • /etc/init.d/mongos-new

mongos起動スクリプトをコピーして修正します。


mongos起動


  • command

$ sudo service mongos-new start


シャードの設定

新mongosの設定完了済みのサーバで作業する


シャード追加

$ mongo --port=37017

mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("56c081bccabb5eff10c1c995")
}
shards:
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
mongos> sh.addShard("mongodb_replicaset00/172.16.11.21:27017");
{ "shardAdded" : "mongodb_replicaset00", "ok" : 1 }
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("56c081bccabb5eff10c1c995")
}
shards:
{ "_id" : "mongodb_replicaset00", "host" : "mongodb_replicaset00/172.16.11.21:27017,172.16.11.22:27017,172.16.11.23:27017" }
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }


テスト用データベースとコレクションの作成

newmongodbデータベースを作り、コレクションnewshard_testを作成する。


  • mongosでの作業

mongos> use newmongodb

mongos> db.createCollection("newshard_test");
{
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(1455458157, 1),
"electionId" : ObjectId("56c07ea680f80b802b651ba2")
}
}


  • replica set member(primary)での確認

mongos経由で作成したデータベースとコレクションが、PRIMARYからも確認できる。

$ mongo --port=37017

mongodb_replicaset00:PRIMARY> show dbs
config 0.000GB
local 0.000GB
newmongodb 0.000GB
mongodb_replicaset00:PRIMARY> use newmongodb
switched to db newmongodb
mongodb_replicaset00:PRIMARY> show collections;
newshard_test


テストドキュメントの挿入


  • newmongodb.newshard_testにnewshard_testというドキュメントを挿入する

mongos> db.createCollection("newshard_test");

{
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(1455458157, 1),
"electionId" : ObjectId("56c07ea680f80b802b651ba2")
}
}

これで新mongodb clusterの準備が整いました。


mongodbのデータ移行


  • サービス停止

輪廻転生するモンゴを使うサービスにDB writeが走らないよう、メンテ入れするなりします。


移行元の環境からmongodump


  • Balancerの停止とmongodump

今回は前提条件の通りにmongos経由でmongodumpします。

dump前にBalancerを止めておきます。


  • - Balancerの停止

移行対象のmongodb cluster全てに対してBalancer停止コマンドを実行します。

$ mongo --port=27017

mongos> sh.status();
mongos> sh.stopBalancer();
mongos> sh.disableBalancing(true);
mongos> sh.status();
※Balancerが停止していること
$ mongo --port=27117
mongos> sh.status();
mongos> sh.stopBalancer();
mongos> sh.disableBalancing(true);
mongos> sh.status();
※Balancerが停止していること


  • mongodump

mongodb clusterの数だけmongos経由でmongodumpを実行します。

$ mongodump --port=27017 --out=mongodbcluster_shard_dump

$ mongodump --port=27117 --out=mongocluster2_shard_dump


移行先の環境へmongorestore

db数分mongorestoreを実行します。


  • full restoreはエラーになる

config databaseはリストアできませんよとエラーが出ます。

$ mongorestore --port=37017 --dir=mongodbcluster_shard_dump/

2016-02-14T23:50:39.692+0900 building a list of dbs and collections to restore from mongodbcluster_shard_dump/ dir
2016-02-14T23:50:39.693+0900 Failed: cannot do a full restore on a sharded system - remove the 'config' directory from the dump directory first


  • db単位でmongorestoreする

$ mongorestore --port=37017 --db=mongodb --dir=mongodbcluster_shard_dump/mongodb/

2016-02-14T23:51:25.823+0900 building a list of collections to restore from mongodbcluster_shard_dump/mongodb/ dir
2016-02-14T23:51:25.860+0900 reading metadata file from mongodbcluster_shard_dump/mongodb/mongocollection.metadata.json
2016-02-14T23:51:25.862+0900 restoring mongodb.mongocollection from file mongodbcluster_shard_dump/mongodb/mongocollection.bson
2016-02-14T23:51:27.035+0900 restoring indexes for collection mongodb.mongocollection from metadata
2016-02-14T23:51:27.054+0900 finished restoring mongodb.mongocollection (33 documents)
2016-02-14T23:51:27.054+0900 done


移行後確認

移行したコレクション内のドキュメント件数をチェックします。

移行前/移行後同じ件数なので無事移行できました。


  • 移行前のコレクション内ドキュメント件数

$ mongo --port=27017

MongoDB shell version: 3.0.9
connecting to: 127.0.0.1:27017/test
mongos> use mongodb;
switched to db mongodb
mongos> db.mongocollection.find().count();
33


  • 移行後のコレクション内ドキュメントの件数

$ mongo --port=37017

MongoDB shell version: 3.0.9
connecting to: 127.0.0.1:37017/test
mongos> use mongodb;
switched to db mongodb
mongos> db.mongocollection.find().count();
33


  • shardの状態を確認

移行前に設定していたシャードキーが剥がれちゃってます。

が、今回は1シャードに縮小したので戻す必要はないです。

mongos> sh.status()

--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("56c081bccabb5eff10c1c995")
}
shards:
{ "_id" : "mongodb_replicaset00", "host" : "mongodb_replicaset00/172.16.11.21:27017,172.16.11.22:27017" }
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "newmongodb", "partitioned" : false, "primary" : "mongodb_replicaset00" }
{ "_id" : "mongodb", "partitioned" : false, "primary" : "mongodb_replicaset00" }

mongos>


アプリケーション(mongos)新環境への切替


  • アプリケーションのmongosエンドポイントを新環境にアクセスするように変更します。

  • 移行前環境のmongodbクラスタにアクセスするmongosを停止します。

以上で移行と切替は完了です。


移行前環境の破棄

切替後、特に問題なければ移行前のmongodbクラスタを破棄します。

ささやき えいしょう いのり terminate

おわり。


おまけ


シャードのスケールイン

今回のように作り直しするのではなく、シャードだけスケールインしたい時は、オンラインで可能です。

removeShardを使います。

removeShardは2回実行する必要があります。

draining -> dropの順で状態が変化します。


  • シャードのdraining

mongos> sh.status();

移行前のシャード状態を確認する
mongos> use admin
mongos> db.runCommand( { removeShard: "shard01" } );
{
"msg" : "draining ongoing",
"state" : "ongoing",
"remaining" : {
"chunks" : NumberLong(0),
"dbs" : NumberLong(2)
},
"note" : "you need to drop or movePrimary these databases",
"dbsToMove" : [
"mongocollection",
"test"
],
"ok" : 1
}


  • シャードの確認とPrimaryシャードの変更

コレクションの所属するPrimaryシャードが削除対象のシャードだった場合、

2回目のremoveShard実行時に以下のようなエラーメッセージが発生します。


  • 削除対象のシャードにPrimaryコレクションが存在するとエラー

mongos> db.runCommand( { removeShard: "shard01" } );

{
"msg" : "draining ongoing",
"state" : "ongoing",
"remaining" : {
"chunks" : NumberLong(0),
"dbs" : NumberLong(2)
},
"note" : "you need to drop or movePrimary these databases",
"dbsToMove" : [
"mongocollection",
"test"
],
"ok" : 1
}


  • コレクションのPrimaryシャード変更

mongos> sh.status();

チャンクが全て残すシャードに寄ったことを確認します。
mongos> db.runCommand( { movePrimary: "mongocollection", to :"shard00" } );
{
"primary " : "shard00:shard00/172.16.10.21:27017,172.16.10.22:27017,172.16.10.23:27017",
"ok" : 1
}
mongos> sh.status()
コレクションのPrimaryシャードが削除対象ではないシャードになっていることを確認する


  • シャードの削除

チャンクが全て残存シャードに移動していること。

コレクションのPrimaryシャードが残存シャードとなっていること。

以上がOKだったらシャードを削除します。さよなら~

mongos> use admin

mongos> db.runCommand( { removeShard: "shard01" } );
{
"msg" : "removeshard completed successfully",
"state" : "completed",
"shard" : "shard01",
"ok" : 1
}

おわりのおわり。