MongoDB 3.2 でレプリカセットを構築する



3台のサーバ（mongo1、mongo2、mongo3）でレプリカセットを構築
OSはCentOS7を使用
本家[マニュアル](https://docs.mongodb.org/manual/)をリファレンスに実施しました

OS環境準備
----

とりあえずyum updateを適用

```console
# yum update -y
```

MongoDBのデータ用にDisk（60GB）を追加し、LVMを作成
ファイルシステムはxfs
データ保存パス/data/dbにマウントする

```console
# pvcreate /dev/sdb
# vgcreate mongoVg /dev/sdb
# lvcreate -n mongoLv -l 100%FREE mongoVg
# mkfs.xfs /dev/mongoVg/mongoLv
# mkdir /data
# mkdir /data/db
# mount /dev/mapper/mongoVg-mongoLv /data/db
# df -h
ファイルシス                サイズ  使用  残り 使用% マウント位置
/dev/mapper/centos-root        18G  1.1G   17G    6% /
devtmpfs                      907M     0  907M    0% /dev
tmpfs                         917M     0  917M    0% /dev/shm
tmpfs                         917M  8.3M  909M    1% /run
tmpfs                         917M     0  917M    0% /sys/fs/cgroup
/dev/sda1                     494M  166M  328M   34% /boot
tmpfs                         184M     0  184M    0% /run/user/1000
/dev/mapper/mongoVg-mongoLv    60G   33M   60G    1% /data/db
```

これで、DBのデータ領域として/data/dbにデータ領域が作成できました。
また、mongo1、mongo2、mongo3が相互に名前解決可能なようにhostsに追記しておきます。


MongoDB 3.2インストール
----

MongoDBのリポジトリを追加（[公式ドキュメント参照](https://docs.mongodb.org/master/tutorial/install-mongodb-on-red-hat/))するため、`/etc/yum.repos.d/mongodb-org-3.2.repo`を作成

```/etc/yum.repos.d/mongodb-org-3.2.repo
[mongodb-org-3.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.2/x86_64/
gpgcheck=0
enabled=1
```

```console
# yum install -y mongodb-org-server-3.2.3 mongodb-org-shell-3.2.3 mongodb-org-tools-3.2.3
```

設定・起動
----

mongodの設定ファイル`/etc/mongod.conf`が作成されます。

```/etc/mongod.conf
# cat /etc/mongod.conf
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# Where and how to store data.
storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:

# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all interfaces.


#security:

#operationProfiling:

#replication:

#sharding:

## Enterprise-Only Options

#auditLog:

#snmp:
```

dbPathなどいろいろ修正が必要なので、yaml形式で新規作成しました。

```/etc/mongod.yml
systemLog:
    destination: file
    logAppend: true
    path: /var/log/mongodb/mongod.log
storage:
    dbPath: /data/db
    journal:
       enabled: true
    engine: "wiredTiger"
    wiredTiger:
        engineConfig:
            directoryForIndexes: true
            cacheSizeGB: 1
processManagement:
    fork: true
    pidFilePath: /var/run/mongodb/mongod.pid
net:
    port: 27017
replication:
    replSetName: "rs-db"
```

作成したデータディレクトリの所有者を変更しておきます。

```console
# chown -R mongod:mongod /data/
```

設定ファイルをymlに変更しましたので、initスクリプトの`CONFIGFILE`のパスを変更しておきます。

```/etc/rc.d/init.d/mongod
# CONFIGFILE="/etc/mongod.conf"
CONFIGFILE="/etc/mongod.yml"
```

```console
# chkconfig mongod on
# /etc/rc.d/init.d/mongod start
```

ここまでの作業を3台のサーバ全てで実施しておきます。

レプリカセット構築
----

ここからはPrimaryDBとなるmongo1で実施します。

mongoShellでDBに接続

```console
# mongo
```

admin DBに切替

```console
> use admin
switched to db admin
```

レプリカセットの初期構築

```console
> rs.initiate()
{
        "info2" : "no configuration specified. Using a default configuration for the set",
        "me" : "mongo1:27017",
        "ok" : 1
}
rs-db:SECONDARY>
rs-db:PRIMARY>
rs-db:PRIMARY>
```

プロンプトに`mongod.yml`で指定したレプリカセット名`rs-db`が表示され`PRIMARY`の状態となる

続いて管理用ユーザ`dbadmin`を作成

```console
rs-db:PRIMARY> db.createUser({ user: "dbadmin", pwd: "********", roles: [{ role: "root", db: "admin" }]})
Successfully added user: {
        "user" : "dbadmin",
        "roles" : [
                {
                        "role" : "root",
                        "db" : "admin"
                }
        ]
}
```

ユーザを作成すると未認証での操作ができなくなるので入りなおし

```console
$ mongo localhost:27017/admin -u dbadmin -p
MongoDB shell version: 3.2.3
Enter password:
connecting to: localhost:27017/admin
Server has startup warnings:
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten]
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten]
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten]
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 4096 processes, 64000 files. Number of processes should be at least 32000 : 0.5 times number of files.
2016-02-28T10:33:55.836+0900 I CONTROL  [initandlisten]
rs-db:PRIMARY>
```

たくさん警告メッセージがでますが、こちらの抑止については後述

```console
rs-db:PRIMARY> show dbs
admin  0.000GB
local  0.000GB
rs-db:PRIMARY> db.system.users.find()
{ "_id" : "admin.dbadmin", "user" : "dbadmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "W91BUAmHg+IQDBTHP3caJQ==", "storedKey" : "MeDkofLaL42A0QfQrGdBTNY6HB4=", "serverKey" : "gq9thZq/dC7EoHEuG/CmUV6w8/4=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
```

`admin`、`local`の2つのdbがあり、`admin`DBに`dbadmin`ユーザが作成されています

現在のレプリカセット状態を表示

```console

rs-db:PRIMARY> rs.conf()
{
        "_id" : "rs-db",
        "version" : 1,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "mongo1:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                }
        }
}
```

ここに、mongo2、mongo3の2つのホストをレプリカセットに追加します。

```console
rs-db:PRIMARY> rs.add( { host: "mongo2:27017"} )
{ "ok" : 1 }
rs-db:PRIMARY> rs.add( { host: "mongo3:27017"} )
{ "ok" : 1 }
rs-db:PRIMARY> rs.conf()
{
        "_id" : "rs-db",
        "version" : 3,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "mongo1:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

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

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

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                }
        }
}
```

レプリカセットのステータスを表示

```console
rs-db:PRIMARY> rs.status()
{
        "set" : "rs-db",
        "date" : ISODate("2016-02-28T11:10:31.900Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "heartbeatIntervalMillis" : NumberLong(2000),
        "members" : [
                {
                        "_id" : 0,
                        "name" : "mongo1:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 122,
                        "optime" : {
                                "ts" : Timestamp(1456744206, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2016-02-28T11:10:06Z"),
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1456744148, 2),
                        "electionDate" : ISODate("2016-02-28T11:09:08Z"),
                        "configVersion" : 3,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "mongo2:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 29,
                        "optime" : {
                                "ts" : Timestamp(1456744206, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2016-02-28T11:10:06Z"),
                        "lastHeartbeat" : ISODate("2016-02-28T11:10:30.543Z"),
                        "lastHeartbeatRecv" : ISODate("2016-02-28T11:10:31.576Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "mongo1:27017",
                        "configVersion" : 3
                },
                {
                        "_id" : 2,
                        "name" : "mongo3:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 25,
                        "optime" : {
                                "ts" : Timestamp(1456744206, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2016-02-28T11:10:06Z"),
                        "lastHeartbeat" : ISODate("2016-02-28T11:10:30.570Z"),
                        "lastHeartbeatRecv" : ISODate("2016-02-28T11:10:28.740Z"),
                        "pingMs" : NumberLong(0),
                        "configVersion" : 3
                }
        ],
        "ok" : 1
}
```

以上で、mongo1、mongo2、mongo3の3台でのレプリカセットrs-dbが完成です


補足：接続時の警告メッセージ抑止
----

警告は3.0のときと同様で、[MongoDB 3.0インストール後のワーニングの消し方](http://qiita.com/hmitr/items/dcf70e3106d513b9967b)を参考に対応することで消すことが可能でした。

おわりに
----
ここまでは3.0のときと変化点はありませんでした。
次はシャードクラスタの構築を行いたいと思います。
シャードについてはconfigサーバがレプリカセットに対応したなど、3.0とはいくつか変化点がありそうです。