MongoDB on AWS Cloud その2:ストレージエンジンをWiredTigerにしてみた

2016.09.30

こんにちは、菊池です。クラスメソッドに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がデフォルトになっています。

構成

前回のエントリで構築した環境をそのまま利用します。

starting-mongo-aws-01

作業対象はClusterに参加しているPrimary/Secondaryの3ノードです。

作業手順

大まかには以下の通りです。

  1. Secondary00を停止し、ストレージエンジンを変更
  2. Secondary00を起動しデータ同期を実施
  3. Secondary01に対し上記1, 2 を実施
  4. 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以降を使うのであれば既存のデータも可能な限り移行していくことをおすすめします。