Skip to content

Droongaノードの死活管理をSerfで行う手順

piroor edited this page Sep 26, 2014 · 33 revisions

実験環境の構築手順に基づいて、以下の3ノードがセットアップ済みであると仮定する。

  • node0: 192.168.100.50
  • node1: 192.168.100.51
  • node2: 192.168.100.52

Serfのインストール

各ノード上で行う。

  1. ダウンロードページからバイナリを入手し、パスの通ったディレクトリに実行ファイルを設置する。

    % wget https://dl.bintray.com/mitchellh/serf/0.5.0_linux_amd64.zip
    % unzip 0.5.0_linux_amd64.zip
    % sudo mv serf /usr/local/bin/
    

Serfの挙動について

Serfの起動

  1. 各ノードでサービスを起動する。ノード名とバインド先IPアドレスは、自分自身を指す値とする。 ここではポート番号の指定を省略しており、Serf既定のポート7946が使われる。

    (node0)
    % serf agent -node=node0 -bind=192.168.100.50 \
                 -event-handler=/path/to/command \
                 -log-level=debug
    ----
    (node1)
    % serf agent -node=node1 -bind=192.168.100.51 \
                 -event-handler=/path/to/command \
                 -log-level=debug
    ----
    (node2)
    % serf agent -node=node2 -bind=192.168.100.52 \
                 -event-handler=/path/to/command \
                 -log-level=debug
    
    • この時、各ノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-join
      • stdin: node0 192.168.100.50

クラスタへの明示的な参加

  1. サービスを起動したコンソールとは別のコンソールで、他のノードのIPアドレスを指定してserf joinを実行する。

    (node0)
    % serf join 192.168.100.51
    % serf join 192.168.100.52
    ----
    (node1)
    % serf join 192.168.100.50
    % serf join 192.168.100.52
    ----
    (node2)
    % serf join 192.168.100.50
    % serf join 192.168.100.51
    
    • join先は、クラスタを構成する自分以外のノードであれば誰でも構わない。 (実際の運用時は、catalog.jsonからIPアドレスを収集してくることになる?)
    • 複数回joinしても問題ない。 (ただし、既にjoin済みの場合はエラーのイベントが発生するようなので、あるノードへのjoinに失敗したら次のノードにjoinを試みる、といった形でfallbackするのがよさそう。)
    • この時、各ノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-join
      • stdin: node1 192.168.100.51\nnode2 192.168.100.52
  2. クラスタへの参加に成功したかどうか、serf membersコマンドで確認する。

    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  alive
    node2  192.168.100.52:7946  alive
    

クラスタからの明示的な離脱と再参加

  1. どれか1つのノード(例えばnode1)でSerfのプロセスを終了してみる。 するとイベントが自動的にメンバーに通知されて、各メンバーが持つメンバーリストが更新される。

    • serf leaveを実行しても、自動的にプロセスが終了する。
    • この時、クラスタに残されたノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-leave
      • stdin: node1 192.168.100.51
  2. 他のノード(node0かnode2)でserf membersしてみる。

    (node0)
    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  left
    node2  192.168.100.52:7946  alive
    

    leftとなっているのが、離脱中のノードである。

  3. 離脱したノードで再度Serfを起動する。

    (node1)
    % serf agent -node=node1 -bind=192.168.100.51 \
                 -event-handler=/path/to/command \
                 -log-level=debug
    

    この時点ではまだ、このノードはクラスタに復帰していない。

    (node0)
    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  left
    node2  192.168.100.52:7946  alive
    ----
    (node1)
    % serf members
    node1  192.168.100.51:7946  alive
    
  4. 再度クラスタに参加する。node1から他のノードへserf joinする。

    (node1)
    % serf join 192.168.100.50
    
    • この時、クラスタに残っていたノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-join
      • stdin: node1 192.168.100.51
  5. クラスタへの参加に成功したかどうか、serf membersコマンドで確認する。

    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  alive
    node2  192.168.100.52:7946  alive
    

障害によるクラスタからの離脱と再参加(すぐに再接続できるパターン)

  1. どれか1つのノード(例えばnode1)で、serfのプロセスを強制終了してみる。 すると、残ったノードに対してイベントが自動的に通知されて、各メンバーが持つメンバーリストが更新される。

    • この時、クラスタに残されたノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-failed.
      • stdin: node1 192.168.100.51
  2. 他のノード(node0かnode2)でserf membersしてみる。

    (node0)
    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  failed
    node2  192.168.100.52:7946  alive
    

    failedとなっているのが、障害発生により暗黙的に離脱中のノードである。

  3. 離脱したノードのserfをもう一度起動する。

    • この時、クラスタに残っていたノードでは一定時間ごとのポーリングによりノードの復帰が検知され、自動的に、イベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-join
      • stdin: node1 192.168.100.51
    • serfを起動し直したノードでは、「自分がjoin」のイベントが発生した後、しばらく経ってから「クラスタに残っていたほか野ノードがjoin」のイベントが発生する。
  4. クラスタへの復帰に成功したかどうか、serf membersコマンドで確認する。

    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  alive
    node2  192.168.100.52:7946  alive
    

障害によるクラスタからの離脱と再参加(重篤な障害のパターン)

  1. どれか1つのノード(例えばnode1)のVMをリセットしてみる。 すると、残ったノードに対してイベントが自動的に通知されて、各メンバーが持つメンバーリストが更新される。

    • この時、クラスタに残されたノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-failed.
      • stdin: node1 192.168.100.51
  2. 他のノード(node0かnode2)でserf membersしてみる。

    (node0)
    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  failed
    node2  192.168.100.52:7946  alive
    

    failedとなっているのが、障害発生により暗黙的に離脱中のノードである。

  3. 離脱したノードのVMを再開し、serf agentを実行してサービスを起動する。

    • この時、クラスタに残っていたノードでは一定時間ごとのポーリングによりノードの復帰が検知され、自動的に、イベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: member-join
      • stdin: node1 192.168.100.51
    • 復帰したノードの側でも、クラスタに残っていたノードからのメッセージによりserf joinが自動的に実行される。
  4. クラスタへの復帰に成功したかどうか、serf membersコマンドで確認する。

    % serf members
    node0  192.168.100.50:7946  alive
    node1  192.168.100.51:7946  alive
    node2  192.168.100.52:7946  alive
    

クラスタ全体への任意のメッセージの通知

  1. クラスタに参加中のノードからイベントを送る。

    (node0)
    % serf event "my-event" "my-data"
    
    • この時、クラスタに所属しているノードではイベントハンドラに以下の情報が渡される(以下はnode0の場合)。
      • $SERF_EVENT: user
      • $SERF_USER_EVENT: my-event
      • stdin: my-data
    • 他のノードだけでなく、自分自身にも同時に通知される。

特定ノードへの任意のメッセージの通知

  1. クラスタに参加中のノードからイベントを送る。

    (node0)
    % serf query -node=node1 "my-event" "my-data"
    
    • この時、-node オプションで指定されたノードではイベントハンドラに以下の情報が渡される(以下はnode1の場合)。
      • $SERF_EVENT: query
      • $SERF_USER_QUERY: my-event
      • stdin: my-data
    • 自分自身にも通知できる。
    • 関係ないノードには通知されない。

Droonga Engineとの連携プラン

  • Serfのインストールと起動はChefで自動化しておくのが望ましいか?
  • Serfのイベントハンドラとして機能するコマンドをDroonga Engineの bin/droonga-handle-serf-event として含める。 このコマンドの働きは以下の通りとする。
    • member-join, member-leave, member-failedイベントの受信時:liveなノードのリスト(ファイル)を更新する。
    • user, queryイベントの受信時:ノードの死活状態の変更に関するものであった場合、liveなノードのリスト(ファイル)を更新する。
    • ノードのリストのファイルの位置は、以下のようにしてコマンドライン引数で指定する。 serf agent -event-handler="droonga-handle-serf-event --list=/path/to/list-file"
    • イベントを受信した際は、内部でserf membersを実行し、完全な情報を元にその都度完全なリストを生成することにする。
  • Serfのノード名は、Droonga Engineのボリュームのaddresshost:port/tag.dbにおけるhostの部分に揃える。
  • Droonga Engineは、初期状態で、catalog.jsonに記述されているすべてのノードがliveであると想定したliveなノードのリストを持つ。
  • Droonga Engineは、メッセージを配送する必要が生じた時は、メモリ上にあるliveなノードのリストに基づいて配送先を決定する。
  • Droonga Engineは、liveなノードのリスト(ファイル)が書き換えられたことを何らかの方法で検知して、メモリ上にあるliveなノードのリストを破棄し、ファイルから最新のliveなノードのリストを読み込む。
    • Serfが起動した時点で「自分しかノードがいないクラスタに参加した」という事を意味するイベントを受信するが、それをトリガーとして、初期状態のliveなノードのリストはすぐに破棄され、自分だけが生きているという内容のliveなノードのリストがメモリ上に保持された状態となる。
  • SerfとDroonga Engineは、互いにliveなノードのリスト(ファイル)のみを通じて連携しあう。お互いがお互いのプロセスを直接起動するということはない。
    • これは、依存関係を可能な限り断ち切り、自動テストを容易に行えるようにするために、有効な方針である。
  • Droonga Engineは、guard/listenを使ってファイルの変更を監視する。
    • guard/listenは、ファイルの変更を監視するコマンドラインツールとして知られるguardが内部的に使用しているライブラリである。
Clone this wiki locally