このところ、Serfのコードを読んでいました。一旦、読んで理解した内容をまとめてみたいと思います。

Packages

Serfは大きく次の2つのパッケージに分かれており、各々の役割は以下のようになっています。

memberlist

serf

そして、serfはパッケージはmemberlistパッケージに依存しています。 serf1

今回はmemberlistについて分かったことを書いていきます。

Memberlist Summary

memberlistはSerfクラスタの各ノード内に1つずつ存在しており、Serfクラスタ内の全ノード情報を保持しています。この保持しているノード情報が、Serfクラスタのノード間でやり取り(full state sync)されることで、ノード情報が伝播していきます。 serf2

また、各ノードは定期的に他のノードにpingを送信して生存確認を行います(probe)。この結果がNGだった場合、自身のノード情報を更新し、NGノードの情報を他のノードに送信して行きます(gossip)。 serf6

また、新しいノードがSerfクラスタに参加した場合も、自身のノード情報を更新し、新たに参加したノードの情報を他のノードに送信します(gossip)。 serf4

また、ノード間の情報のやり取りとは別に、各ノード内でSerfクラスタのノードの状態等が変更されると、その変更内容によってイベントが発火する仕組みがあります(event delegate)。 serf5

Reading README.md

まず、memberlistのREADME.mdに記載されている内容を確認しています。訳は適当ですので、各自で確認してください。

Protocol Description

Changes from SWIM

Node state management

memberlistでは、ノード間で以下のメッセージをやり取りすることで、各ノードの状態を管理しています。メッセージを送信する間隔はconfigによって変更できます。以下はDefaultLANConfigに設定されている間隔です。

Probe

probeはUDPでノードの生存をチェックします。

まず、自身が保持するノード情報から生存チェック対象とするノードを選択します。このノードはprobeが実行される度に順に1つ選ばれ、最後までチェックしたらまた最初からチェックします。

対象ノードにpingメッセージを送信し、ackが返ってくればチェック完了です。ackが返ってこない場合は、自身が保持するノード情報からランダムに複数のノードを選択(DefaultLANConfigの場合は3)し、その選択したノードから対象ノードにpingメッセージを送信します(indirectPing)。 serf3

それでもackが返ってこない場合は、対象ノードをsuspect(疑わしい)とみなし、その情報を他のノードに伝播します。

Full state sync(pushPull)

full state sync(pushPull)はTCPを使い、2つのノード間でお互いが保持するノード情報を同期します。

まず、自身が保持するノード情報をランダムに1つ選び、それを対向側のノードとします。そしてその対向側のノードに対し、自身が保持するノード情報を送信します。これには、ホスト名、IPアドレス、通信ポート、そのノードの状態などが含まれます。

次に、対向側のノードが保持するノード情報を受信します。そして各ノード情報について自身のノード情報と比較し、異なる場合は更新して他のノードに伝播します。

対向側から見ると、full state syncを受信時に送信元からノード情報を受け取り、自身のノード情報を送信します。これはTCPリスナが担当します。

Gossip

gossipはprobeやpushPull以外の以下のメッセージを各ノードに送信します。

これらのメッセージは各ノードのbroadcastキューに登録されています。あるノードのstateを他のノードに伝播したい場合は、一旦broadcastキューに登録します。gossipではbroadcastキューからメッセージを取得し、ランダムに選択した複数(DefaultLANConfigの場合は3)のノードに対してそのメッセージを送信します。

gossipにより送信されたメッセージを受信する側は、受信したメッセージによって適切な処理を実行します。これはUDPリスナが担当します。

Node status

ノードの状態は以下の3つが定義されています。

Delegate

config.DelegateにDelegateを設定しておくと、以下が発生した契機に各ハンドラが呼び出されます。

Event propergation

conig.EventsにEventDelegateを設定しておくと、ノードの状態が変化した際に以下のイベントが発火し、EventDelegateのイベントハンドラが呼び出されます。

Conclusion

今回はmemberlistのコードを読んで分かったことを記載しました。近いうちにserfについても書いてみようと思います。serfの方はまだcommandとagentの部分を読んでないので、時間を作って読んでみたいと思います。