MongoDB on AWS Cloud その2:ストレージエンジンをWiredTigerにしてみた
こんにちは、菊池です。クラスメソッドにJOINして1ヶ月が経ちました。
先日のブログで、AWSクイックスタート:MongoDB on the AWS Cloudを試してみたという記事を書きました。MongoDBクラスタを簡単に構築できるCloudFormationテンプレートでしたが、公開から若干時間が経っているため、以下のような改善点があると記載しました。
- MongoDBのストレージエンジンをWiredTigerにする
- MongoDB 3.0 からストレージエンジンとしてWiredTigerが使用可能になっていますが、デフォルトではMMAPv1となります。WiredTigerを使うことで、データ圧縮や、書き込み性能の大幅向上などのメリットがあります。
そこで今回は、テンプレートから構築したMongoDBクラスタのストレージエンジンをWiredTigerにアップグレードしてみたいと思います。
WiredTiger StorgeEngine とは
MongoDB Manual : WiredTiger Storage Engine
MongoDB Ver 3.0から採用されたストレージエンジンで、それまでのMMAPv1に比べて以下のような優位性があります。
データ圧縮
MongoDBはJOSNドキュメントを保管しますので、各項目のkey:valueがそのまま記載されます。そのため、RDBに比べてデータの物理的なサイズが肥大しがちです。データ圧縮が可能になったことで、データボリュームの肥大化を抑えることができます。
ロックの改善
MongoDB Ver 2.6まではデータ更新時のロックがデータベースレベルロックでした。そのため、書き込みが多い用途ではロック待ちが大きくなっていました。Ver 3.0以降で採用されたWiredTigerを使うことで、ドキュメントレベルロック(RDBの行ロックに相当)になりますので、ロック待ち時間が劇的に削減され、書き込み性能が大幅に向上されました。
なお、MongoDB Ver 3.2系ではWiredTigerがデフォルトになっています。
構成
前回のエントリで構築した環境をそのまま利用します。
作業対象はClusterに参加しているPrimary/Secondaryの3ノードです。
作業手順
大まかには以下の通りです。
- Secondary00を停止し、ストレージエンジンを変更
- Secondary00を起動しデータ同期を実施
- Secondary01に対し上記1, 2 を実施
- Primary00に対し上記1, 2 を実施
レプリカセットのクラスタでは異なるストレージエンジンを混在可能ですので、上記のようにローリングアップデートを実施することで、オンラインのまま作業が可能です。
Secondaryのストレージエンジン変更
まずはPrimaryでレプリカセットの状態を確認します。
s0-rs0:PRIMARY> rs.status() { "set" : "s0-rs0", "date" : ISODate("2016-09-30T09:15:11.013Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "10.0.2.243:27018", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 516, "optime" : Timestamp(1475226404, 1), "optimeDate" : ISODate("2016-09-30T09:06:44Z"), "electionTime" : Timestamp(1475226407, 1), "electionDate" : ISODate("2016-09-30T09:06:47Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "10.0.4.32:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 507, "optime" : Timestamp(1475226404, 1), "optimeDate" : ISODate("2016-09-30T09:06:44Z"), "lastHeartbeat" : ISODate("2016-09-30T09:15:10.730Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:15:10.742Z"), "pingMs" : 2, "configVersion" : 1 }, { "_id" : 3, "name" : "10.0.3.244:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 507, "optime" : Timestamp(1475226404, 1), "optimeDate" : ISODate("2016-09-30T09:06:44Z"), "lastHeartbeat" : ISODate("2016-09-30T09:15:10.228Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:15:10.237Z"), "pingMs" : 0, "configVersion" : 1 } ], "ok" : 1 }
3台とも認識されています。Secodary00にログインし、mongod0のサービスを停止します。
$ sudo service mongod0 stop Stopping mongod: [ OK ]
もう一度Primaryで状態を確認すると、
s0-rs0:PRIMARY> rs.status() { "set" : "s0-rs0", "date" : ISODate("2016-09-30T09:17:21.357Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "10.0.2.243:27018", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 646, "optime" : Timestamp(1475226404, 1), "optimeDate" : ISODate("2016-09-30T09:06:44Z"), "electionTime" : Timestamp(1475226407, 1), "electionDate" : ISODate("2016-09-30T09:06:47Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "10.0.4.32:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 637, "optime" : Timestamp(1475226404, 1), "optimeDate" : ISODate("2016-09-30T09:06:44Z"), "lastHeartbeat" : ISODate("2016-09-30T09:17:20.908Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:17:20.932Z"), "pingMs" : 2, "configVersion" : 1 }, { "_id" : 3, "name" : "10.0.3.244:27018", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(0, 0), "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2016-09-30T09:17:20.313Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:16:30.285Z"), "pingMs" : 0, "lastHeartbeatMessage" : "Failed attempt to connect to 10.0.3.244:27018; couldn't connect to server 10.0.3.244:27018 (10.0.3.244), connection attempt failed", "configVersion" : -1 } ], "ok" : 1 } s0-rs0:PRIMARY>
Secondayが1ノード通信できない状態となっています。
ストレージエンジン変更のため、/etc/mongod0.confを編集します。
変更前:
$ cat /etc/mongod0.conf net: port: 27018 systemLog: destination: file logAppend: true path: /log/mongod0.log storage: dbPath: /data/s0-rs0 journal: enabled: true processManagement: fork: true pidFilePath: /var/run/mongod/mongod0.pid replication: replSetName: s0-rs0
変更後:
$ cat /etc/mongod0.conf net: port: 27018 systemLog: destination: file logAppend: true path: /log/mongod0.log storage: dbPath: /data/s0-rs0 journal: enabled: true engine: "wiredTiger" wiredTiger: engineConfig: cacheSizeGB: 1 directoryForIndexes: true statisticsLogDelaySecs: 0 collectionConfig: blockCompressor: "snappy" processManagement: fork: true pidFilePath: /var/run/mongod/mongod0.pid replication: replSetName: s0-rs0
blockCompressor: "snappy"
は圧縮の方式で、圧縮率と不可のバランスをとった形式です。
そして、dbPath: /data/s0-rs0
以下にあるデータを全て削除します。
$ sudo rm -rf /data/s0-rs0/*
なかなか抵抗があるコマンドですが、データを全て削除し、再度起動することでレプリカセットの他のノードからデータを再同期します。この再同期の際に、新たに設定したWiredTigerの形式でデータが再構成されます。
そして、mongod0を起動します。
$ sudo service mongod0 start Starting mongod: [ OK ]
Primaryで状態を確認すると、
s0-rs0:PRIMARY> rs.status() { "set" : "s0-rs0", "date" : ISODate("2016-09-30T09:28:33.664Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "10.0.2.243:27018", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1318, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "electionTime" : Timestamp(1475226407, 1), "electionDate" : ISODate("2016-09-30T09:06:47Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "10.0.4.32:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 1309, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "lastHeartbeat" : ISODate("2016-09-30T09:28:31.896Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:28:31.917Z"), "pingMs" : 2, "syncingTo" : "10.0.2.243:27018", "configVersion" : 1 }, { "_id" : 3, "name" : "10.0.3.244:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 128, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "lastHeartbeat" : ISODate("2016-09-30T09:28:33.054Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:28:33.066Z"), "pingMs" : 0, "syncingTo" : "10.0.2.243:27018", "configVersion" : 1 } ], "ok" : 1 } s0-rs0:PRIMARY>
正しく認識されています。
同様の手順をSecodary01でも実施します。
Primaryのストレージエンジン変更
続いてPrimaryです。
Secondaryと同様、Primaryノードのmongod0プロセスを停止します。
$ sudo service mongod0 stop Stopping mongod: [ OK ]
起動しているSecondaryにログインし、状態を確認します。
s0-rs0:SECONDARY> rs.status() { "set" : "s0-rs0", "date" : ISODate("2016-09-30T09:32:44.057Z"), "myState" : 2, "members" : [ { "_id" : 1, "name" : "10.0.2.243:27018", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(0, 0), "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2016-09-30T09:32:43.217Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:31:25.040Z"), "pingMs" : 0, "lastHeartbeatMessage" : "Failed attempt to connect to 10.0.2.243:27018; couldn't connect to server 10.0.2.243:27018 (10.0.2.243), connection attempt failed", "configVersion" : -1 }, { "_id" : 2, "name" : "10.0.4.32:27018", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 379, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "lastHeartbeat" : ISODate("2016-09-30T09:32:43.458Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:32:42.330Z"), "pingMs" : 2, "electionTime" : Timestamp(1475227888, 1), "electionDate" : ISODate("2016-09-30T09:31:28Z"), "configVersion" : 1 }, { "_id" : 3, "name" : "10.0.3.244:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 380, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "configVersion" : 1, "self" : true } ], "ok" : 1 } s0-rs0:SECONDARY>
Primaryだったノードが接続不能になり、Secondaryの1台がPrimaryに昇格しています。このようにMongoDBのレプリカセットではPrimaryが停止すれば自動でいずれかのSecondaryが昇格します。
あとはこれまでのSecondaryと同様です。設定変更後、起動します。再度状態を確認すると、
s0-rs0:SECONDARY> rs.status() { "set" : "s0-rs0", "date" : ISODate("2016-09-30T09:35:02.123Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "10.0.2.243:27018", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 9, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "electionTime" : Timestamp(1475228097, 1), "electionDate" : ISODate("2016-09-30T09:34:57Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "10.0.4.32:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 8, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "lastHeartbeat" : ISODate("2016-09-30T09:35:01.759Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:35:01.126Z"), "pingMs" : 2, "configVersion" : 1 }, { "_id" : 3, "name" : "10.0.3.244:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 8, "optime" : Timestamp(1475227704, 1), "optimeDate" : ISODate("2016-09-30T09:28:24Z"), "lastHeartbeat" : ISODate("2016-09-30T09:35:01.749Z"), "lastHeartbeatRecv" : ISODate("2016-09-30T09:35:01.476Z"), "pingMs" : 0, "configVersion" : 1 } ], "ok" : 1 } s0-rs0:PRIMARY>
Primaryが元に戻っています。レプリカセット設定によりプライオリティが高いノードが復帰すれば、自動でPrimaryに昇格します。
s0-rs0:PRIMARY> rs.conf() { "_id" : "s0-rs0", "version" : 1, "members" : [ { "_id" : 1, "host" : "10.0.2.243:27018", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 10, "tags" : { }, "slaveDelay" : 0, "votes" : 1 }, { "_id" : 2, "host" : "10.0.4.32:27018", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 5, "tags" : { }, "slaveDelay" : 0, "votes" : 1 }, { "_id" : 3, "host" : "10.0.3.244:27018", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 5, "tags" : { }, "slaveDelay" : 0, "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatTimeoutSecs" : 10, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 } } } s0-rs0:PRIMARY>
以上でストレージエンジンの変更は完了です。
変更前後のデータパスの構成を確認してみます。
変更前:
$ ls -l /data/s0-rs0/ 合計 21125172 lrwxrwxrwx 1 mongod mongod 15 9月 30 09:06 journal -> /journal/s0-rs0 -rw------- 1 mongod mongod 67108864 9月 30 09:34 local.0 -rw------- 1 mongod mongod 2146435072 9月 30 09:28 local.1 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.10 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.2 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.3 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.4 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.5 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.6 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.7 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.8 -rw------- 1 mongod mongod 2146435072 9月 30 09:06 local.9 -rw------- 1 mongod mongod 16777216 9月 30 09:34 local.ns -rw-r--r-- 1 mongod mongod 6 9月 30 09:34 mongod.lock -rw-r--r-- 1 mongod mongod 69 9月 30 09:06 storage.bson -rw------- 1 mongod mongod 67108864 9月 30 09:28 testDB.0 -rw------- 1 mongod mongod 16777216 9月 30 09:28 testDB.ns
変更後:
ls -l /data/s0-rs0/ 合計 176 -rw-r--r-- 1 mongod mongod 46 9月 30 09:26 WiredTiger -rw-r--r-- 1 mongod mongod 533 9月 30 09:26 WiredTiger.basecfg -rw-r--r-- 1 mongod mongod 21 9月 30 09:26 WiredTiger.lock -rw-r--r-- 1 mongod mongod 875 9月 30 09:29 WiredTiger.turtle -rw-r--r-- 1 mongod mongod 61440 9月 30 09:29 WiredTiger.wt -rw-r--r-- 1 mongod mongod 36864 9月 30 09:29 _mdb_catalog.wt drwxr-xr-x 2 mongod mongod 4096 9月 30 09:28 collection drwxr-xr-x 2 mongod mongod 4096 9月 30 09:28 index drwxr-xr-x 2 mongod mongod 4096 9月 30 09:26 journal -rw-r--r-- 1 mongod mongod 6 9月 30 09:26 mongod.lock -rw-r--r-- 1 mongod mongod 36864 9月 30 09:29 sizeStorer.wt -rw-r--r-- 1 mongod mongod 95 9月 30 09:26 storage.bson
変更前後で構造は大きく変わっています。WiredTigerでは、IndexやDB単位でディレクトリを分けることも可能です。
まとめ
テンプレートから構築したクラスタのストレージエンジン変更手順を紹介しました。
今、MongoDBを使うのであればWiredTigerを利用しない理由はありませんので、Ver 3.0以降を使うのであれば既存のデータも可能な限り移行していくことをおすすめします。