Dec 6, 2011

RabbitMQ の高可用構成について

本稿は CloudFoundry Advent Calendar の 6日目の記事として投稿させて頂いています.

本当はどの辺りをいじったら CloudFoundry から RabbitMQ を cluster setup できるのか調査…したかったのだが,そこまで終わらなかったので,VMware つながり && 昨日の y_wakai さんによる RabbitMQ の記事つながりで, RabbitMQ のクラスタセットアップについてまとめておく.

RabbitMQ は 2.6.x から複数台による Active-Active Standby 構成をとることができる.以前は DRBD による Active-Stanby 構成しかとれなかったので,2.6 以降で,より柔軟性が上がっている.

前準備
最新の RabbitMQ をインストールするには,http://www.rabbitmq.com/install-debian.html が参考になる.インストールが終了し,RabbitMQ がマシン h1, h2, h3 で動作していると仮定する.
まず,高可用構成をとるには,RabbitMQ のインスタンス識別子である cookie を同一にしておく必要がある.Debian の場合,cookie ファイルは /var/lib/rabbitmq/.erlang.cookie にある.もし編集していない場合は,

h1 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie
h2 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie
h3 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie

などとして,クラスタに参加させたいノードの cookie を併せておく.

前知識
高可用構成のセットアップに入る前に,いくつかクラスタセットアップに必要なクラスタのノードの種類について説明する.クラスタのノードの種類には RAM ノードと Disk ノードの2種類がある.その名前の通り,RAM ノードのキューの状態はメモリの中にのみ保存され永続化は行われない.一方,Disk ノードのキューの状態は外部記憶に永続化される.ただし,複数台 Disk モードで動作させたとしても,複製はディスクに書くことを保証しないので注意.DRBD の Bモードで動作させている状態だと思えば良い.高可用構成のクラスタ内には,最低でも1台の Disk ノードが必要なので注意.

高可用構成のセットアップ
高可用構成のセットアップを行うには. rabbitmqctl コマンドを用いる.

h2 $ rabbitmqctl stop_app          # Erlang は起動させたまま RabbitMQ プロセスを停止
h2 $ rabbitmqctl reset             # RabbitMQ の保持している状態,および DB を初期化
h2 $ rabbitmqctl cluster rabbit@h1 # rabbitmq@h1 をディスクノード,rabbitmq@h2 をRAMノードにしてセットアップ
h2 $ rabbitmqctl start_app          # RabbitMQ プロセスを再開

これで,h1 をDiskノード, h2 を RAMノードにしてセットアップが完了した.
ポイントとしては, rabbitmqctl cluster で選択したノードが Disk ノードになることだ.
クラスタの状態を調べるには rabbitmq cluster_status を使う.
h1 $ rabbitmqctl cluster_status # クラスタ設定を調べる
[{nodes,[{disc,[rabbit@h1]},{ram,[rabbit@h2]}]},
 {running_nodes,[rabbit@h1,rabbit@h2]}]

h2 $ rabbitmqctl cluster_status
[{nodes,[{disc,[rabbit@h1]},{ram,[rabbit@h2]}]}, {running_nodes,[rabbit@h1,
rabbit@h2
]}]


disc,となっているのが Disk ノード,ram となっているのが RAM ノードである.
3台構成でも同様に行ける.

h3 $ rabbitmqctl stop_app          # Erlang は起動させたまま RabbitMQ プロセスを停止
h3 $ rabbitmqctl reset             # RabbitMQ の保持している状態,および DB を初期化
h3 $ rabbitmqctl cluster rabbit@h1 # rabbitmq@h1 をディスクノード,rabbitmq@h2 をRAMノードにしてセットアップ
h3 $ abbitmqctl start_app          # RabbitMQ プロセスを再開

h1 $ rabbitmqctl cluster_status 
h2 $ rabbitmqctl cluster_status
h3 $ rabbitmqctl cluster_status
h1 と h2 など,複数ノードを disc ノードにしたい場合は,
rabbitmqctl cluster rabbit@h1 rabbit@h2
とすれば良い.

ついでに,昨日の記事にもあった Bunny のライブラリについての補足もしておく.
Bunny のドキュメント中には,リモートの RabbitMQ の接続を行う方法が記述されていない.その方法を知るには,コードを読んで追いかける必要がある.以前調査を行ったので,以下に,リモートの RabbitMQ に接続して enqueue, deque するサンプルを示す.ポイントは,Bunny.new する箇所で :host でホストネームを渡してあげる部分.
#!/usr/bin/env ruby
require "bunny"

if ARGV.size < 3
  puts "Arguments Error! "
  exit(1)
end

hostname = ARGV.shift.to_s
num = ARGV.shift.to_i
msgsize = ARGV.shift.to_i

b = Bunny.new(:host => hostname, :persistent=>false, :immediate=>true)
val = "a" * msgsize
# start a communication session with the amqp server
b.start
b.tx_select
# declare a queue
q = b.queue("test1")
# declare default direct exchange which is bound to all queues
e = b.exchange("")


def push(b, e, num, val)
  num.times do |num|
    # publish a message to the exchange which then gets routed to the queue
    e.publish(val, :key => 'test1')
    b.tx_commit
  end
end

def pop(q)
  while msg = q.pop(:ack => true)[:payload]
    if msg == :queue_empty
      break
    else
      q.ack
    end
  end
end

push(b, e, num, val)
pop(q)
というわけで,次回こそは RabbitMQ と vcap のについて追いかけて説明したい.


No comments:

Post a Comment