MongoDBでレプリケーションを試してみよう

## はじめに

この記事では MongoDB を使って、レプリケーションを試してみます。

レプリケーションを試してみようと思ったきっかけは、結果整合性を理解したかったからです。

結果整合性とは、「更新はそのうち反映される」とか「結果的に整合性が保たれる」とか紹介されています。ちょっと分かりにくいです。

- [結果整合性 - Wikipedia](https://ja.wikipedia.org/wiki/%E7%B5%90%E6%9E%9C%E6%95%B4%E5%90%88%E6%80%A7)
- [Amazon S3 の結果整合性と読み取り一貫性 ｜ Developers.IO](http://dev.classmethod.jp/cloud/amazon-s3-eventually-consistent-and-consistent-read/)
- [CAPとBASEとEventually Consistent](http://www.slideshare.net/yohei/capbaseeventually-consistent?type=presentation)

NoSQLの話だと気付き、どのようなDBを使えば結果整合性を確認できそうか調べてみたところ、

MongoDBが良さそうだったので、今回はMongoDBを使うことにしました。

ひとまず、参考になった記事を紹介します。

- [特集：MongoDBで理解する「ドキュメント・データベース」の世界（前編）：開発者が知っておくべき、ドキュメント・データベースの基礎 (1/3) - ＠IT](http://www.atmarkit.co.jp/ait/articles/1211/09/news056.html)
- [MongoDB超入門 - Qiita](http://qiita.com/saba1024/items/f2ad56f2a3ba7aaf8521)
- [MongoDBでらくらくバッチ処理をやる(Javascriptファイルを実行する)方法 · DQNEO起業日記](http://dqn.sakusakutto.jp/2012/04/mongodb-batch-javascript.html)
- [Getting Started with MongoDB (Node.js Edition) — Getting Started With MongoDB 3.0.4](http://docs.mongodb.org/getting-started/node/)
（特に、「A brief overview of the Node.js Driver」がオススメです。）
- [MongoDBのレプリケーションが簡単すぎる… - (ﾟ∀ﾟ)o彡 sasata299's blog](http://blog.livedoor.jp/sasata299/archives/51423059.html)

この記事では、MongoDBのインストール、データベースサーバの起動、クライアントの起動、データの保存・検索、マスター＆スレーブの構成、レプリケーションについて紹介します。

## インストール

MongoDB をインストールするために次のコマンドラインを実行します。

```
$ sudo rudix install mongodb
```

## mongod サーバーを起動

mongod を起動するために、次のコマンドラインを実行します。

```
$ mongod --dbpath db/mongo
```

--dbpath でデータベースのパスを指定します。データベースのパスを指定しないでデータベースサーバーを起動したところ、エラーになりました。

## mongo クライアントを起動

mongo を起動するために、次のコマンドラインを実行します。

```
$ mongo
```

## レプリケーションを試してみる

master サーバと slave サーバを用意します。

まずは master サーバを起動します。

```
$ mongod --master --dbpath db/mongo/master
```

次に slave サーバーを起動します。

```
$ mongod --slave --port 27018 --source localhost --dbpath db/mongo/slave
```

master サーバと slave サーバを用意したので、レプリケーションを試してみます。

レプリケーションを確認するために、クライアントから master サーバに接続して、データを保存します。そして、その保存したデータが slave サーバにも反映されることを確認します。

まずは、クライアントから master サーバと slave サーバに接続して、初期状態を確認します。

クライアントを起動するときに --port で接続先のポート番号を指定することができます。指定しない場合、ポート番号は 27017 になります。

```
% mongo
MongoDB shell version: 2.6.0
connecting to: test
Server has startup warnings:
2015-08-25T01:19:09.501+0900 [initandlisten]
2015-08-25T01:19:09.501+0900 [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
> show dbs
admin  (empty)
local  0.328GB
>
```

ここでは slave サーバに接続するのに、ポート番号を指定します。

```
% mongo --port 27018
MongoDB shell version: 2.6.0
connecting to: 127.0.0.1:27018/test
Server has startup warnings:
2015-08-25T01:19:26.509+0900 [initandlisten]
2015-08-25T01:19:26.509+0900 [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
> show dbs
admin  (empty)
local  0.078GB
>
```

次に、master サーバでデータを保存・検索します。

```
> use study
switched to db study
> db.study.insert({ name: 'taro', age: '123' })
WriteResult({ "nInserted" : 1 })
> db.study.find({ name: 'taro' })
{ "_id" : ObjectId("55db45e6ee1edad9b5e25d59"), "name" : "taro", "age" : "123" }
>
```

最後に、保存したデータが slave サーバにも反映されることを確認します。

```
> use study
switched to db study
> db.study.find({ name: 'taro' })
{ "_id" : ObjectId("55db45e6ee1edad9b5e25d59"), "name" : "taro", "age" : "123" }
>
```

_id の値も同じですね。master サーバで保存したデータが slave サーバにも反映されましたので、レプリケーションが確認できました。

## レプリケーションを遅延させてみる

slave サーバーを起動するときに --slavedelay オプションを指定することでレプリケーションを遅延させることができます。

次のようなコマンドラインでレプリケーションを遅延させることができます。

```
$ mongod --slave --port 27018 --source localhost --slavedelay 180 --dbpath db/mongo/slave
```

ここではレプリケーションを180秒だけ遅延させるように指定します。

まずは、master サーバでデータを保存・検索します。

```
> db.study.insert({ name: 'tokyo'})
WriteResult({ "nInserted" : 1 })
> db.study.find({ name: 'tokyo' })
{ "_id" : ObjectId("55db49beee1edad9b5e25d5b"), "name" : "tokyo" }
>
```

次に、slave サーバで保存したデータを検索します。

```
> db.study.find({ name: 'tokyo' })
>
```

データを保存した直後だと検索はヒットしませんが、しばらく待つとヒットするようになります。

```
> db.study.find({ name: 'tokyo' })
{ "_id" : ObjectId("55db49beee1edad9b5e25d5b"), "name" : "tokyo" }
```

_id の値も同じですね。

結果整合性の「更新はそのうち反映される」が体験できたと思います。

## まとめ

MongoDBを使ってレプリケーションを試してみました。そして、結果整合性を体験しました。

slave サーバで__use study__を忘れると、180秒待ったはずだけど、検索がヒットしないみたいなことになります。気を付けましょう。