RabbitMQでクラスタリング・ミラーリングをする


## クラスタリングとは？

* 複数のホスト（ノード）間で、connection, vhost, queue（メッセージ）を共有すること
 * 片方のホストでユーザ追加・vhost追加・メッセージ登録すると、もう片方のホストにも反映される（参照も同じ）
* ２台の内、１台のRabbitMQがダウンしても、メッセージは消失しない
* 詳しくはRabbitMQ Clustering Guide参照
 * https://www.rabbitmq.com/clustering.html

## ミラーリングとは？
* queue（＋メッセージ）を同期すること
* クラスタリングだけでも、メッセージは同期するが、メッセージ本体はmasterのホストにしか存在しない。その為、masterのホストがダウンすると、そのメッセージは消失する
* どのホストにもメッセージ本体を持つにはミラーリングが必要

## クラスタリングの条件

 * クラスタリングするホスト同士のRabbitMQバージョンが同じであること（3桁目だけ違うのはOK) 
    * NG: 2.x.x <=> 3.x.x
    * NG: 3.1.x <=> 3.2.x
    * OK: 3.2.x <=> 3.2.y
 * クラスタリングするホスト同士の`/var/lib/rabbitmq/.erlang.cookie`の値が同一であること
 * `/var/lib/rabbitmq/.erlang.cookie`の権限が400、所有者・グループがrabbitmqであること

  ```
  ll -la /var/lib/rabbitmq | grep erlang.cookie
  -r--------   1 rabbitmq rabbitmq   20 Sep 19 07:40 .erlang.cookie
  ```

  * クラスタリング用のポートが開いていること
    * デフォルトでは`25672`
    * 正確には`RABBITMQ_NODE_PORT` + 20000。`RABBITMQ_NODE_PORT`がデフォルトで5672なので、25672となる
    * クライアントが使用するのは`RABBITMQ_NODE_PORT=5672`なので、異なることに注意
  * ホスト名が名前解決できること(IPアドレスではできない）

## クラスタリング方法
* サーバー停止 

```
$ sudo /usr/sbin/rabbitmqctl stop_app
```

* リセット（エラーになったら`reset`を`force_reset`で実行）

```
$ sudo /usr/sbin/rabbitmqctl reset
```

* クラスタ設定

```
$ sudo /usr/sbin/rabbitmqctl join_cluster rabbit@<host_name>
```

* サーバー起動

```
$ sudo /usr/sbin/rabbitmqctl start_app
```

## クラスタリング設定確認

* クラスタリング確認コマンド

```
$ sudo /usr/sbin/rabbitmqctl cluster_status
```

* 実行結果（クラスタリング設定されている場合）

```
Cluster status of node 'rabbit@host-001' ...
[{nodes,[{disc,['rabbit@host-001','rabbit@host-002']}]},
 {running_nodes,['rabbit@host-002','rabbit@host-001']},
 {cluster_name,<<"rabbit@host-001">>},
 {partitions,[]}]
...done.
```
running_nodesに`rabbit@host-001`,`rabbit@host-002`がある


* 実行結果（クラスタリング設定されているが、host-002が落ちている場合）
 
```
Cluster status of node 'rabbit@host-001' ...
[{nodes,[{disc,['rabbit@host-001','rabbit@host-002']}]},
 {running_nodes,['rabbit@host-001']},
 {cluster_name,<<"rabbit@host-001">>},
 {partitions,[]}]
...done.
```
running_nodesに`rabbit@host-002`が無い


## クラスタリング解除

```
$ sudo /usr/sbin/rabbitmqctl stop_app
$ sudo /usr/sbin/rabbitmqctl reset
$ sudo /usr/sbin/rabbitmqctl start_app
```
ただし、`reset`により、vhost・permission・queueも削除されるので、別途再作成が必要


## ミラーリング方法

```
$ sudo /usr/sbin/rabbitmqctl set_policy all '^.*' '{"ha-mode": "all"}' -p <vhost>
```
`"ha-mode": "all"`とすることで、クラスタのすべてのホストでキューを同期する（個別のホストも指定可能）

```text:vhost=/productionの場合
$ sudo /usr/sbin/rabbitmqctl set_policy all '^.*' '{"ha-mode": "all"}' -p /production
```
```text:実行結果
Setting policy "all" for pattern "^.*" to "{\"ha-mode\": \"all\"}" with priority "0" ...
...done.
```

## ミラーリング確認

* rabbitmqctl list_policiesの場合

```
$ sudo /usr/sbin/rabbitmqctl list_policies -p <vhost>
```

```text:vhost=/productionの場合
$ sudo /usr/sbin/rabbitmqctl list_policies -p /production
```

```text:実行結果
Listing policies ...
/production     all     all     ^.*     {"ha-mode":"all"}       0
...done.
```

* rabbitmqctl list_queuesの場合

```
$ sudo /usr/sbin/rabbitmqctl list_queues -p <vhost> name slave_pids
```

```text:vhost=/productionの場合
$ sudo /usr/sbin/rabbitmqctl list_queues -p /production name slave_pids
```

```text:実行結果
Listing queues ...
queue1   [<rabbit@host-001.2.19604.890>]
...done.
```
`<rabbit@xxxx.x.xxxx.xxx>`みたいに値が入っていればＯＫ（ミラーリングされていないとブランク）

## ミラーリングの注意点
* ミラーリングされていないキューに対して、`set_policy`でミラーリング設定することは可能。ただし、`set_policy`の前に登録されているメッセージはミラーリングされない