LoginSignup
16

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-02-14

俺です。
満を持して準備した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
}

おわりのおわり。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16