MongoDB Enterprise Advanced:In-Memoryストレージエンジンを構築する

2017.07.24

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

こんにちは、菊池です。

MongoDBの商用ライセンスであるMongoDB Enterprise Advanced、前回はインストール手順を紹介しました。

MongoDB Enterprise Advancedをインストールする

今回は、商用版のみの機能の1つである、In-Memoryストレージエンジンの構築について紹介します。

In-Memoryストレージエンジン

In-Memoryストレージエンジンは、その名の通り、メモリ内にデータを保持することで高速なクエリパフォーマンスを実現します。MongoDB Enterpriseのバージョン3.2.6以降で利用可能です。

メモリにデータを保持するため、そのインスタンスでは永続化されず、mongodプロセスが再起動すると書き込まれた全てのデータは消えてしまいます。そのため、単体ではキャッシュなどの一時的なデータの格納に利用するのが適しています。

永続化が必要なデータの保管にはレプリカセットを利用することで、データを保全しつつ、高パフォーマンスな環境の構築が可能です。MongoDBでは異なるストレージエンジンを組み合わせてレプリカセットを構成できます。アプリケーションからのアクセスをIn-Memoryストレージエンジンのノートで処理し、データの永続化のためにWiredTigerストレージエンジンを使うことで、In-Memoryのパフォーマンスを提供しつつ、データの永続化が可能になります。

mongodb-ea-inmemory

WiredTigerのノードはHiddenとして指定することで、クライアントからはアクセスされない状態とすることができます。今回はこの構成で構築します。なお、レプリカセットの構成パターンは以下を合わせて参照ください。

構築手順

それでは、In-Memoryのレプリカセット環境を構築していきます。

前提環境

設定ファイルの作成

各ノードの/etc/mongod.confを編集します。In-Memoryストレージエンジンを利用する、ノード:mongo0/mongo1の設定は以下のようになります。

$ cat /etc/mongod.conf
net:
  port: 27017

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

storage:
  engine: inMemory
  dbPath: /data
  inMemory:
    engineConfig:
      inMemorySizeGB: 1

processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/mongod.pid
replication:
  replSetName: s0

データの永続化を行うHiddenとなるノード:mongo2は以下のように記述します。ストレージエンジンを指定しなければ、バージョン3.2以降でデフォルトのWiredTigerとなります。

$ cat /etc/mongod.conf
net:
  port: 27017

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

storage:
  dbPath: /data

processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/mongod.pid
replication:
  replSetName: s0

データディレクトリの作成

データディレクトリを作成します。In-Memoryの場合にも、データは保存されませんが作成が必要です。

$ sudo mkdir /data
$ sudo chown mongod:mongod /data

レプリカセットの作成

準備ができましたので、mongodを起動しましょう。

$ sudo systemctl start mongod
$ mongo
MongoDB shell version v3.4.6
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.6
Server has startup warnings:
2017-07-24T08:05:52.920+0900 I CONTROL  [initandlisten]
2017-07-24T08:05:52.921+0900 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-07-24T08:05:52.921+0900 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-07-24T08:05:52.921+0900 I CONTROL  [initandlisten]
MongoDB Enterprise >

ノード:mongo0レプリカセットの設定を行っていきます。

MongoDB Enterprise > rs.initiate( { _id : "s0", members: [ { _id : 0, host : "mongo0:27017" } ]})
{ "ok" : 1 }
MongoDB Enterprise s0:SECONDARY>
MongoDB Enterprise s0:PRIMARY>

レプリカセットにノード:mongo1/2を追加します。mongo2はpriority: 0hidden: trueを指定します。

MongoDB Enterprise s0:PRIMARY> rs.add( { _id : 1,  host: "mongo1:27017" , priority: 1, votes: 1 } )
{ "ok" : 1 }
MongoDB Enterprise s0:PRIMARY> rs.add( { _id : 2,  host: "mongo2:27017" , priority: 0, votes: 1 , hidden: true } )
{ "ok" : 1 }

レプリカセットの状態を確認します。

MongoDB Enterprise s0:PRIMARY> rs.status().members
[
       	{
       		"_id" : 0,
       		"name" : "mongo0:27017",
       		"health" : 1,
       		"state" : 1,
       		"stateStr" : "PRIMARY",
       		"uptime" : 1060,
       		"optime" : {
       			"ts" : Timestamp(1500852207, 1),
       			"t" : NumberLong(1)
       		},
       		"optimeDate" : ISODate("2017-07-23T23:23:27Z"),
       		"electionTime" : Timestamp(1500851725, 2),
       		"electionDate" : ISODate("2017-07-23T23:15:25Z"),
       		"configVersion" : 3,
       		"self" : true
       	},
       	{
       		"_id" : 1,
       		"name" : "mongo1:27017",
       		"health" : 1,
       		"state" : 2,
       		"stateStr" : "SECONDARY",
       		"uptime" : 442,
       		"optime" : {
       			"ts" : Timestamp(1500852207, 1),
       			"t" : NumberLong(1)
       		},
       		"optimeDurable" : {
       			"ts" : Timestamp(0, 0),
       			"t" : NumberLong(-1)
       		},
       		"optimeDate" : ISODate("2017-07-23T23:23:27Z"),
       		"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
       		"lastHeartbeat" : ISODate("2017-07-23T23:23:32.364Z"),
       		"lastHeartbeatRecv" : ISODate("2017-07-23T23:23:31.342Z"),
       		"pingMs" : NumberLong(0),
       		"syncingTo" : "mongo0:27017",
       		"configVersion" : 3
       	},
       	{
       		"_id" : 2,
       		"name" : "mongo2:27017",
       		"health" : 1,
       		"state" : 2,
       		"stateStr" : "SECONDARY",
       		"uptime" : 422,
       		"optime" : {
       			"ts" : Timestamp(1500852207, 1),
       			"t" : NumberLong(1)
       		},
       		"optimeDurable" : {
       			"ts" : Timestamp(1500852207, 1),
       			"t" : NumberLong(1)
       		},
       		"optimeDate" : ISODate("2017-07-23T23:23:27Z"),
       		"optimeDurableDate" : ISODate("2017-07-23T23:23:27Z"),
       		"lastHeartbeat" : ISODate("2017-07-23T23:23:32.370Z"),
       		"lastHeartbeatRecv" : ISODate("2017-07-23T23:23:31.528Z"),
       		"pingMs" : NumberLong(0),
       		"syncingTo" : "mongo1:27017",
       		"configVersion" : 3
       	}
]

各ノードが正しく認識されました。設定が正しいか確認します。

MongoDB Enterprise s0:PRIMARY> rs.conf().members
[
       	{
       		"_id" : 0,
       		"host" : "mongo0:27017",
       		"arbiterOnly" : false,
       		"buildIndexes" : true,
       		"hidden" : false,
       		"priority" : 1,
       		"tags" : {

       		},
       		"slaveDelay" : NumberLong(0),
       		"votes" : 1
       	},
       	{
       		"_id" : 1,
       		"host" : "mongo1:27017",
       		"arbiterOnly" : false,
       		"buildIndexes" : true,
       		"hidden" : false,
       		"priority" : 1,
       		"tags" : {

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

       		},
       		"slaveDelay" : NumberLong(0),
       		"votes" : 1
       	}
]

ストレージエンジンの確認です。ノード:mongo0/1ではinMemoryとなっています。persistent: falseから、データの永続性がないこともわかります。

MongoDB Enterprise s0:PRIMARY> db.serverStatus().storageEngine
{
       	"name" : "inMemory",
       	"supportsCommittedReads" : true,
       	"readOnly" : false,
       	"persistent" : false
}

一方で、mongo2はwiredTigerとなっており、persistent: trueです。

MongoDB Enterprise s0:SECONDARY> db.serverStatus().storageEngine
{
       	"name" : "wiredTiger",
       	"supportsCommittedReads" : true,
       	"readOnly" : false,
       	"persistent" : true
}

データ永続性の確認

実際に、データを書き込み、レプリケーションによりデータが保全されることを確認します。

MongoDB Enterprise s0:PRIMARY> use test
switched to db test
MongoDB Enterprise s0:PRIMARY> db.users.insert({name:"hoge"});
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise s0:PRIMARY> db.users.find()
{ "_id" : ObjectId("597530c5a400db8f5b4dfc17"), "name" : "hoge" }

書き込めたので、mongodを再起動してみます。

MongoDB Enterprise s0:PRIMARY> exit
bye
$ sudo systemctl restart mongod
$ mongo
MongoDB shell version v3.4.6
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.6
Server has startup warnings:
2017-07-24T08:27:42.331+0900 I CONTROL  [initandlisten]
2017-07-24T08:27:42.331+0900 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-07-24T08:27:42.331+0900 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-07-24T08:27:42.331+0900 I CONTROL  [initandlisten]
MongoDB Enterprise s0:SECONDARY>

再起動によりフェイルオーバーが発生してますので、SECONDARYとなっています。データを読み込んでみましょう。

MongoDB Enterprise s0:SECONDARY> rs.slaveOk()
MongoDB Enterprise s0:SECONDARY> db.users.find()
{ "_id" : ObjectId("597530c5a400db8f5b4dfc17"), "name" : "hoge" }

先ほど書き込んだデータが、再起動後にも残っていることが確認できました。

まとめ

以上でIn-Memoryストレージエンジンのレプリカセットが構築できました。今後、In-Memoryのパフォーマンスについても検証してみたいと思います。