Tech Sketch Bucket of Technical Chips by TIS Inc.

RabbitMQを使ってみる〜クラスタリング編〜

Pocket

この記事はeXcale Developer's Blogから移転されたものです。

eXcale開発チームの泉谷(@syguer)です。
今回は前回に続き、Message QueuingのためのミドルウェアであるRabbitMQでクラスタリングする方法について紹介します。


※本記事ではバージョン3.x以降のクラスタ設定について紹介しています。2.x系とはコマンドや設定方法が異なる場合があります。

RabbitMQのクラスタリング

RabbitMQではすべてのノードが起動しているactive/active構成でクラスタリングを行います。
クラスタリングは以下の2つの要素で実現されています。

1.クラスタ
複数のRabbitMQノードに互いを認識させてクラスタを構成します。
クラスタのノード同士は、5672(TCP)ポートをつかってお互いに死活を監視します。
監視の間隔はデフォルトで60秒となっています。
また、クラスタを構成するとノード間でキューを共有します。

2.Mirrored Queue
クラスタに所属しているノードはキューを共有しますが、キュー自体はミラーリングはされていないため、キューを持っているノードがダウンすると他のノードからはキューが見えなくなります。
そこで、Mirrored Queueを設定することでキュー自体をミラーリングするようになり、可用性を高めることができます。
Mirrored Queueは1台のmasterと複数のslaveで構成されます。
masterのキューに更新がかかったときに、その更新内容をすべてのslaveにも送信することでノード間の同期をしています。

Mirrored Queueのmasterがダウンすると、slaveの中から新たなmasterが選出されます。
選出の基準は稼働時間で、最も稼働時間が長いslaveがmasterになります。
キューは同期されているのでダウンタイムはほとんどないと言う訳です。


ホストの準備

早速クラスタ作成、といきたいのですが、事前にやっておくことについて触れておきます。

・ホストの立ち上げ、ホスト名の解決
RabbitMQではノード名にホスト名を使うため、ホスト名を設定し、お互いに相手の名前を解決できるようにしてください。
以下、本記事では下記設定のホストを使用します。

・hostA (192.168.10.101)
・hostB (192.168.10.102)

※これらのホストでは前回の記事に従ってRabbitMQが稼働しています。

・Erlang cookieの設定
RabbitMQではErlang cookieというErlangノードが作成するcookieを使ってお互いの通信認証をしています。
通信をしたいRabbitMQ同士が使っているErlang coockieが異なると以下のようなエラーがでて通信できません。

これを回避するため、通信するRabbitMQが動いているホストのErlang coockieを揃えます。
Erlang cookieは下記のパスにあります。

これを直接他ホストに渡すか、直接書き換えて値を揃えるようにしてください。

参考リンク
RabbitMQ - Clustering Guide

クラスタの準備

クラスタの設定は、クラスタに追加したいホスト上で設定します。
今回の例ではhostBをhostAのクラスタに追加するのでhostB上で設定します。

※hostAのクラスタに追加すると言っても、hostAのクラスタはまだ作ってないから無いのでは?と思われるかもしれませんが問題ありません。
RabbitMQではクラスタを初期設定する等といった作業は不要です。

下記コマンドをhostBで実行します。

hostBがクラスタに追加されたかどうか確認してみます。
hostA上から下記コマンドを実行してみましょう。

上記のように表示されれば成功です。

ここまでで2台のRabbitMQノードでクラスタを構成することができました。
ここではまだ各ノードがお互いを認識しただけで、キューの同期はされていません。
キューの同期はMirrored Queueを設定して初めて行われます。


Mirrored Queueの設定

次にキューにMirrored Queueの設定をします。
キューでMirrored Queueを有効にするにはポリシーの設定をします。
ポリシーは以下のものが用意されています。

・all
クラスタのすべてのノードでキューを同期します。
通常はこのポリシーで良いと思います。

・exactly
数を指定して、指定した数のノードでキューを同期します。
クラスタに指定した数以上のノードがある場合、ミラーリングされないノードがでてきます。
公式のドキュメントによると、キューのマイグレーションの際に使うとのことです。

・nodes
ノード名を指定して、クラスタの中で指定したノードのみでキューを同期します。

今回はallを指定します。その他のポリシーについては公式ドキュメントを参照してください。

まずキューを作成し、まだミラーリングされていないことを確認します。

次にポリシーを設定します。Mirrored Queueを設定するためのポリシー設定のコマンドは以下の通りです。

"POLICY_NAME"には任意のポリシー名、"QUEUE_NAME"にはポリシーを適用するキュー名を入れてください。
以下のように実行します。

確認のためにrabbitmqadminを使ってキューを見てみます。

このようにslave_nodesとsynchronised_slave_nodesにノードが表示されていれば成功です。


補足:クラスタノードのタイプについて

上記の例では触れていませんでしたが、クラスタノードには"disc"と"ram"というタイプがあります。
二つのタイプの違いは、文字通りデータをメモリ上に全て持つか、ディスクも使うかです。
discに設定した場合ディスクを使うので耐障害性が高まりますがパフォーマンスが落ちます。
ramに設定した場合はパフォーマンスが高まりますが、障害時にデータをロストする可能性があります。
データの損失を防ぎたい場合は、クラスタ内に少なくとも1台はdiscのノードを入れておくと良いとされています。

もう一度クラスタのステータスを確認したところを見てみます。

3行目のところに"disc,"とあると思います。
これはdiscタイプのノードであることを示しています。
ramタイプにノードを変更する場合には以下のようにします。
※変更するノードで実行します

nodesの中にramのノードが増えたのが分かると思います。
ちなみに、クラスタに新規ノードを追加する際にramタイプのノードとして追加したい場合は「--ram」オプションを付けます。


最後に

今回はRabbitMQのクラスタリングについて紹介しました。
Message Queuingを使うことでコンポーネント間の疎結合、処理の非同期化が楽に実現できます。
これを機会にぜひ試してみてください!

エンジニア採用中!私たちと一緒に働いてみませんか?