AWS EC2でMongoDB Shardingをテストしてみた。

awsでmongodbのshardingのテストをするために
ec2のt2.mediumを6台借りて実験。Elastic Ipを使うサーバーは1台だけで
他のサーバーにはAgent Forwardingによりログインする。
各サーバーの容量が8GBなので6台で行っているが、
~~実験するという目的だけでは、sakuraで一台借りてする方が安価にすみそう。~~


mongodbのsharding replicationのアーキテクチャーでは、
config-serverはshard-serverとは別のサーバーに3つ必要らしいので、
今回はawsを複数台借りる選択をした。


各awsは8GBしかないので、実験用の場合に限り、
confのjournalをfalseにすることでデフォルトで設定されるjournalログを無効化して、約3.5GB節約できる。
> 詳細 http://qiita.com/daisuke-3/items/d7e56e8ad788d7150090

しかし、journalをfalseにすると正常に停止しなかった場合に(mongodbを止めずにawsのインスタンスを停止等)データが破損されるので、
後々面倒なことが嫌なので、テスト段階でもjournalは有効にすべきだと判断。

> 詳細 http://docs.mongodb.org/manual/tutorial/recover-data-following-unexpected-shutdown/

#### 課題
同サーバー別ポートでmongodbを起動する場合のserviceコマンド化。
serviceコマンドでは
`/usr/bin/mongod already running.` となり、うまくできない。
なので、
`/usr/bin/mongod -f /etc/mongod_sh*` 起動
~~`kill -KILL PID` 停止
と操作していくしかない。~~
`db.shutdownServer()`で停止。
#### アーキテクチャー

![IMG_1445 のコピー.jpg](https://qiita-image-store.s3.amazonaws.com/0/34498/9dd4e444-3835-436f-9826-ff7aefa7eaa9.jpeg)

aws1(EIP) ... shard1
aws2 ... shard2
aws3 ... shard3
aws4 ... front, config1
aws5 ... front, config2
aws6 ... front, config3


~~aws1でsh2,sh3を削除しても`df -h`コマンドでみる容量が変わらなかったので、
mongodbを再インスコ。でも、する前と変わらなかったのでそのままjournalをtrueにしてsh1を起動。容量表示変わらず。実際にはスペースは空いているが、表示に問題があるよう。~~


#### 手順
aws1,aws2,aws3にsh1,sh2,sh3をそれぞれ作成。
aws4にfront,config1を作成。
config1をaws5,aws6へconfig2,config3としてコピー(
既に動いてあるshardとfront,configは止める)。
>test環境(config-server１台)からproduction環境(config-server3台)へアップグレードする際の手順のドキュメントにてデータディレクトリコピーと書いてある。
Copy the entire dbPath file system tree from the existing config server to the two machines that will provide the additional config servers.

`/etc/init.d/mongod_sh1`を作成する際は、
パーミッションに気をつける。実行権限 `chmod +x mongod_sh1`

まず、認証設定なしで起動。
起動したら、adminユーザー追加。
`use admin`
`db.addUser('root','password')`
`quit()`
して、`service mongod_sh1 stop`
そして、認証設定追加。 `service mongod_sh1 start`
`use admin`
`db.auth('root','password')`で認証。
認証設定の`mongodb.keyfile`は

`openssl rand -base64 753 | sudo tee /etc/mongodb.keyfile`
で作成。パーミッションを気をつける。
`chown mongodb:mongodb mongodb.keyfile`
`chmod 400 mongodb.keyfile`
※利用するアーキテクチャーに一貫性を持たせるために同じkeyfileを使用する。

####設定ファイル
#####/etc/init.d/mongod_sh1
デフォルトだと`mongod -> /lib/init/upstart-job`という風にシンボリックリンクされているが、このupstart-jobは廃止予定らしい(?)ので古い方のSysV initの書き方で設定する。
>詳細 http://blog.livedoor.jp/hack_le/archives/25394608.html

<pre>
#!/bin/sh

### BEGIN INIT INFO
# Provides:          mongod_sh1
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts mongod_sh1 (a rails app)
# Description:       starts mongod_sh1 (a rails app) using start-stop-daemon
### END INIT INFO

USER=mongodb
PID_FILE="/var/run/mongodb/mongod_sh1.pid"
CMD="/usr/bin/mongod"
ARGS="-f /etc/mongod_sh1.conf"

. /lib/lsb/init-functions

case $1 in
  start)
    start-stop-daemon --start --chuid $USER --exec $CMD -- $ARGS || true
    ;;
  stop)
    start-stop-daemon --stop --signal TERM --pidfile $PID_FILE || true
    ;;
  status)
    status_of_proc -p $PID_FILE "$CMD" mongod && exit 0 || exit $?
    ;;
  *)
    echo >&2 "Usage: $0 "
    exit 1
    ;;
esac
</pre>

#####mongod_sh1.conf

<pre>
systemLog:
   destination: file
   path: "/var/log/mongodb/mongod_sh1.log"
   quiet: true
   logAppend: true
storage:
   dbPath: "/var/lib/mongod_sh1"
   journal:
      enabled: true
processManagement:
   fork: true
   pidFilePath: "/var/run/mongodb/mongod_sh1.pid"
net:
   bindIp: aws1
   port: 27017
#replication:
#   replSetName: sh1
sharding:
   clusterRole: shardsvr
security:
   authorization: enabled
   keyFile: /etc/mongodb.keyfile
</pre>
####ログインをスクリプト化
 `bin` ディレクトリ作成。
その下に`vim mongo_sh1`として,実行コマンドを書くことで、
コマンド入力処理を簡易化できる。
`./mongo_sh1`で実行できる。パーミッション`chmod +x mongo_sh1`に気をつける。

<pre>
#!/bin/sh
/usr/bin/mongo aws1:27017/admin
</pre>

`front conf`
※chunkSizeが1なのは実験用のため。

<pre>
systemLog:
   destination: file
   path: "/var/log/mongodb/mongod_front.log"
   quiet: true
   logAppend: true
processManagement:
   fork: true
   pidFilePath: "/var/run/mongodb/mongod_front.pid"
net:
   bindIp: aws4
   port: 20000
sharding:
   configDB: aws4:20001,aws5:20001,aws6:20001
   chunkSize: 1
security:
   keyFile: /etc/mongodb.keyfile
</pre>

`config conf`

<pre>
systemLog:
   destination: file
   path: "/var/log/mongodb/mongod_conf1.log"
   quiet: true
   logAppend: true
storage:
   dbPath: "/var/lib/mongod_conf1"
   journal:
     enabled: true
processManagement:
   fork: true
   pidFilePath: "/var/run/mongodb/mongod_conf1.pid"
net:
   bindIp: aws4
   port: 20001
security:
   authorization: enabled
   keyFile: /etc/mongodb.keyfile
</pre>




~~127.0.0.1 ではなく　localhost~~
bindIPをすべてホスト名にしたらいけた。

awsはデフォルトではpingは通さない
securitygroupでICMPを解放する。

bind ip について
>ドキュメントより、
 net.bindIp
    Type: string
    Default: All interfaces.
    Changed in version 2.6.0: The deb and rpm packages include a default configuration file that sets net.bindIp to 127.0.0.1.
    Specifies the IP address that mongos or mongod binds to in order to listen for connections from applications. You may attach mongos or mongod to any interface. When attaching mongos or mongod to a publicly accessible interface, ensure that you have implemented proper authentication and firewall restrictions to protect the integrity of your database.


~~aws123-4のネットワークの疎通ができていないようなので
ネットワークの設定を行う~~

同じリージョンであればsecuritygroupしかトラフィックを許可する設定の場所はない。

#### 課題
再起動したら`/var/run/mongodb/mongo.pid`
のピッドファイルのmongodbディレクトリごと消えてる問題については、
これはubuntuのtmpfsという機能でRAMに書き込まれるからであって
AWSの問題というより、ubuntu側の問題である。

config server
>http://docs.mongodb.org/manual/core/sharded-cluster-config-servers/
config-serverは必ずテスト環境では１つ、本番環境では３つ使用します。
そして、shard-serverとは別のサーバーを使用します。
3つのconfig-serverが停止したときconfig-serverを立ち上げるまでmongosは再起してはいけません。
config-serverのバックアップは簡単です。
config-serverとclusterを繋ぐためにCNAMEの設定をしている場合、renameやrenumberしたい場合は全てのmongod,mongosを再起動しなければなりません。

起動の順番、停止は（おそらく逆）
設定を変更したら、mongod -> mongoc -> mongosの順番で起動します。

### シャードサーバーを追加する

<pre>
mongos> sh.addShard("aws1:27017") 
mongos> sh.addShard("aws2:27017")
mongos> sh.addShard("aws3:27017")
mongos> sh.status()
追加されているか確認。
</pre>

### テストしてみる

参考:
http://gihyo.jp/dev/serial/01/mongodb/0006?page=2

#### 課題
複数frontサーバーが存在する場合、１つのfrontサーバーをログインしているとき他のサーバーのfrontは立ち上がれなかったような。ReplicaSetの話だっけ・・・

## MongoDBについてメモ
こちら(http://www.slideshare.net/akuwano/cyberagentmongodb )より抜粋。

### システムアーキテクチャー
* スキーマレス  
  機能追加等が比較的楽。
* 冗長化(ReplicaSet)  
  相互死活監視&投票により冗長性を保つ。最小単位は3台(プライマリ、セカンダリx2)
* スケーラビリティ(Sharding)  
  データをChunkサイズに分割することで各サーバーの負荷分散を行う。

### 得意なもの
* データ量が大きすぎない。
* 書き込みが多過ぎでない。
* 単位時間あたりの処理データが各シャードのメモリ量を超えない処理は得意。
* 得意なユースケース  
  * ゲーム系webアプリケーション  
  * 一時的ログ解析基盤  
 
### 苦手なもの
* ほっとデータが無い様なデータの使い方は苦手  
  * データ量が爆発的に増える  
  * 常に全データへのアクセスを行うような
* 苦手なユースケース  
  * ソーシャル系等のWebアプリケーション  
  * 継続的 or 統合的 なログ解析基盤