2007年11月30日

Jabberサーバーをクラスタリングしてみました。

はてなブックマークに登録

みなさん Jabber をご存じですか? Jabber はオープンな仕様のメッセン ジャーサービスのことで最近だと Google Talk で使用している方が多いと思 います。

KLab では 2001年ぐらいから、誰でも Jabber を使うことが出来る Jabber.JP というサービスを運用してい ます。まだ Jabber を使用したことがない方は是非こちらの「Jabber をはじめよう」 を ご覧になって Jabber を使ってみて下さい。

Jabber.JPjabberd という実装を使用してい たのですが、冗長構成が難しいという問題がありました。

そこで先日、Jabber.JP では大規 模なメンテナンスを行い ejabberd という実装で分散、冗長化を行ってみました。ejabberd はその名の通り、Erlang で 実装された Jabber サーバーで、Mnesia データーベースを使用してデータの 冗長化を行うことが出来ます。

今回は Jabber.JP で動いている ejabberd やそのクラスタリング方法について紹介したいと思います。

KLab勉強 会#3 に来られた方は見たことがあるかもしれませんが、こんな感じの構 成です。

Jabber クライアントから jabber.jp:5222(5223) へのアクセスは LVS で 分散され、3台のサーバー(ノード)で動作する ejabberd に割り振られます。 ユーザーアカウントのデータなどは Mnesia のデーターベースに保存され、3 台のノードで動作する Mnesia はマルチマスターレプリケーションを行ってい ます。

この様な構成にすることで、3台のサーバーのうち2台が落っこちてもサー ビスを継続出来るようになっています。

それでは具体的な ejabberd でのクラスタリング方法を紹介します。

まず最初の 1台目の ejabberd を普通に起動します。

$ erl -name ejabberd@host1 -s ejabberd

この状態で、mnesia:info/0 を実行し、データーベースの内容を確認する と以下のような出力が得られます。

opt_disc. Directory "/home/jabberd/Mnesia.ejabberd@host1" is used.
use fallback at restart = false
running db nodes   = [ejabberd@host1]
stopped db nodes   = []
master node tables = []
remote             = []
ram_copies         = [route,s2s,session]
disc_copies        = [acl,
                      config,
                      last_activity,
                      local_config,
                      motd,
                      motd_users,
                      muc_registered,
                      muc_room,
                      passwd,
                      privacy,
                      roster,
                      schema,
                      vcard_search]
disc_only_copies   = [disco_publish,offline_msg,vcard]
[{ejabberd@host1,disc_copies}] = [schema,
                                  acl,
                                  config,
                                  local_config,
                                  passwd,
                                  roster,
                                  privacy,
                                  vcard_search,
                                  motd,
                                  motd_users,
                                  muc_room,
                                  muc_registered,
                                  last_activity]
[{ejabberd@host1,disc_only_copies}] = [disco_publish,vcard,offline_msg]
[{ejabberd@host1,ram_copies}] = [route,session,s2s]

running db nodes, stopped db nodes ではレプリケーションを行っている Mnesia ノードのステータスを確認出来ます。今はレプリケーションを行って いないのでひとつしか表示されていません。

続いて remote, ram_copies, disc_copies, disc_only_copies という 4種 類のテーブルタイプ毎に ejabberd で使用するデーターベーステーブルが表示 されています。remote を除く 3種類のテーブルタイプについては過去の記事 「Erlang版 memcached でキャッシュデータの永続化をしてみました。」をご覧くださ い。

このテーブルタイプ情報をみると、ユーザーからのコネクションを管理す る session テーブルは メモリベース、ユーザーアカウントデータを格納する passwd テーブルはディスクベース、という様に使い分けられていることが分 かります

これで、1台目の ejabberd が動作しましたが、この 1台が落っこちるとサー ビスが停止してしまうので 2台目の ejabberd を追加してみます。

2台目の ejabberd を追加するときはいきなり ejabberd を起動するのでは なく、まず Mnesia だけを起動して、レプリケーションの準備を行います。

$ erl -name ejabberd@host2 -mnesia extra_db_nodes "['ejabberd@host1']" -s mnesia

Mnesia を起動し、host2 で mnesia:info/0 を実行すると以下のように出 力されました。

opt_disc. Directory "/home/jabberd/Mnesia.ejabberd@host2" is NOT used.
use fallback at restart = false
running db nodes   = ['ejabberd@host1','ejabberd@host2']
stopped db nodes   = []
master node tables = []
remote             = [acl,
                      config,
                      disco_publish,
                      last_activity,
                      local_config,
                      motd,
                      motd_users,
                      muc_registered,
                      muc_room,
                      offline_msg,
                      passwd,
                      privacy,
                      roster,
                      route,
                      s2s,
                      session,
                      vcard,
                      vcard_search]
ram_copies         = [schema]
disc_copies        = []
disc_only_copies   = []
[] = [local_config]
[{'ejabberd@host1',disc_copies}] = [last_activity,
                                    muc_registered,
                                    muc_room,
                                    motd_users,
                                    motd,
                                    vcard_search,
                                    privacy,
                                    roster,
                                    passwd,
                                    config,
                                    acl]
[{'ejabberd@host1',disc_copies},
 {'ejabberd@host2',ram_copies}] = [schema]
[{'ejabberd@host1',disc_only_copies}] = [offline_msg,
                                         vcard,
                                         disco_publish]
[{'ejabberd@host1',ram_copies}] = [s2s,session,route]

ejabberd を1台だけ起動したときと異なり、schema を除く全てのテーブル は remote というタイプになっています。これは host2 のノードからデータ ベースにアクセスした場合、間接的に host1 で動作する Mnesia データーベー ステーブルにアクセスすることを意味します。この状態で ejabberd を立ち上 げても正常に動作しますが、データーベースへのアクセスは host1 に集中す ることになり、host1 が落っこちた場合 host2 の ejabberd もサービス不能 に陥ります。

つづいて、host2 にある remote タイプのテーブルをレプリケートしてみ ます。

mnesia:change_table_copy_type(schema, node(), disc_copies).

mnesia:add_table_copy(route, node(), ram_copies).
mnesia:add_table_copy(s2s, node(), ram_copies).
mnesia:add_table_copy(session, node(), ram_copies).

mnesia:add_table_copy(acl, node(), disc_copies).
mnesia:add_table_copy(config, node(), disc_copies).
mnesia:add_table_copy(last_activity, node(), disc_copies).
mnesia:add_table_copy(muc_registered, node(), disc_copies).
mnesia:add_table_copy(muc_room, node(), disc_copies).
mnesia:add_table_copy(motd_users, node(), disc_copies).
mnesia:add_table_copy(motd, node(), disc_copies).
mnesia:add_table_copy(vcard_search, node(), disc_copies).
mnesia:add_table_copy(privacy, node(), disc_copies).
mnesia:add_table_copy(roster, node(), disc_copies).
mnesia:add_table_copy(passwd, node(), disc_copies).

mnesia:add_table_copy(vcard, node(), disc_only_copies).
mnesia:add_table_copy(disco_publish, node(), disc_only_copies).
mnesia:add_table_copy(offline_msg, node(), disc_only_copies).

この様な設定を行った後、host2 で ejabberd を起動して mnesia:info/0 を確認してみます。

 $ erl -name ejabberd@host2 -s ejabberd
opt_disc. Directory "/home/jabberd/Mnesia.ejabberd@host2" is used.
use fallback at restart = false
running db nodes   = ['ejabberd@host1','ejabberd@host2']
stopped db nodes   = []
master node tables = []
remote             = []
ram_copies         = [local_config,route,s2s,session]
disc_copies        = [acl,
                      config,
                      last_activity,
                      motd,
                      motd_users,
                      muc_registered,
                      muc_room,
                      passwd,
                      privacy,
                      roster,
                      schema,
                      vcard_search]
disc_only_copies   = [disco_publish,offline_msg,vcard]
[{'ejabberd@host1',disc_copies},
 {'ejabberd@host2',disc_copies}] = [muc_registered,
                                    muc_room,
                                    schema,
                                    motd_users,
                                    vcard_search,
                                    acl,
                                    motd,
                                    last_activity,
                                    roster,
                                    passwd,
                                    privacy,
                                    config]
[{'ejabberd@host1',disc_only_copies},
 {'ejabberd@host2',disc_only_copies}] = [vcard,
                                         disco_publish,
                                         offline_msg]
[{'ejabberd@host1',ram_copies},
 {'ejabberd@host2',ram_copies}] = [route,s2s,session]
[{'ejabberd@host2',ram_copies}] = [local_config]

remote タイプのテーブルはなくなり、host1, host2 の Mnesia で local_config を除く全てのテーブルをレプリケーションすることが出来まし た。これと同じ要領で 3台目の ejabberd を追加することが出来ます。

Erlang の Mnesia はすこし取っつきにくいかもしれませんが、こんなに簡 単にマルチマスターレプリケーションが出来るのは DBMS としてとても魅力的 だと思います。

耐障害性の高い Jabber サーバーを立ててみようかなと考えている方には、 是非 ejabberd をオススメします。

klab_gijutsu2 at 17:52│Comments(2)TrackBack(1)Erlang 

トラックバックURL

この記事へのトラックバック

1. xmpppy + Python の向こう側  [ Kawasaq通信 ]   2008年01月17日 10:08
先日、Python の xmpppy というパッケージを使えば、簡単に bot が作れるよーという記事を書いたけれど、そのサーバの方はどうなっているのかと調べ...

この記事へのコメント

1. Posted by ejabberd 初心者   2008年02月01日 02:56
質問なのですが、ejabberd がハンドル出来るメッセージのサイズを変更するにはどうすればいいのでしょうか? 32KB までは問題なく送信出来るのですが、64KB になると出来たり出来なかったりします。それ以上だと送受信に失敗してしまいます、、、、
2. Posted by hamano   2008年02月01日 18:24
たしかに、その辺りのサイズのメッセージを送ると、サーバーがエラーを返しますね。
少し追っかけてみると、ejabberd の内部で使用している XML パーサーの libexpat がエラーを返しているようです。
解決方法としては、libexpat で 32K 以上の要素? を扱えるようにしてやる、あるいは libexpat では無く、他の XML パーサー(libxml, xmerl)を使うようにしてやる必要があるかもしれません。
どちらにせよ、ejabberd の改変が必要なのでちょっと大変かもしれませんね。
個人的にはこのぐらいの制限があった方がサーバーに負荷が掛かり過ぎなくてちょうど良いのではないかと思っています^^;

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント