Apache Tribes - はじめに

目次

クイックスタート

Apache Tribesは、リモートオブジェクトを簡単に接続し、相互に通信できるようにするグループ通信またはP2P通信フレームワークです。

  • インポート: org.apache.catalina.tribes.Channel
  • インポート: org.apache.catalina.tribes.Member
  • インポート: org.apache.catalina.tribes.MembershipListener
  • インポート: org.apache.catalina.tribes.ChannelListener
  • インポート: org.apache.catalina.tribes.group.GroupChannel
  • org.apache.catalina.tribes.ChannelListener を実装するクラスを作成する:
  • org.apache.catalina.tribes.MembershipListener を実装するクラスを作成する:
  • メッセージの送信方法をデモンストレーションするシンプルなクラス
    //create a channel
    Channel myChannel = new GroupChannel();
    
    //create my listeners
    ChannelListener msgListener = new MyMessageListener();
    MembershipListener mbrListener = new MyMemberListener();
    
    //attach the listeners to the channel
    myChannel.addMembershipListener(mbrListener);
    myChannel.addChannelListener(msgListener);
    
    //start the channel
    myChannel.start(Channel.DEFAULT);
    
    //create a message to be sent, message must implement java.io.Serializable
    //for performance reasons you probably want them to implement java.io.Externalizable
    Serializable myMsg = new MyMessage();
    
    //retrieve my current members
    Member[] group = myChannel.getMembers();
    
    //send the message
    myChannel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);

シンプルでしょう?Tribesには、これまでに示した以上の多くの機能があります。ドキュメントでさらに詳しく説明できることを願っています。このプロジェクトに役立つと思われる提案、改善、バグ修正、その他何でもいつでも歓迎します。

Tribesとは

Tribesは、グループ通信機能を備えたメッセージングフレームワークです。Tribesを使用すると、ネットワーク経由でメッセージを送受信でき、ネットワーク内の他のノードの動的な検出も可能です。
これが簡単な説明です。実際、これほどシンプルです。Tribesが有用でユニークである理由については、以下のセクションで説明します。

Tribesモジュールは2006年初頭に開始され、そのコードベースの一部は2003年または2004年から存在していたクラスタリングモジュールに由来します。現在のクラスタ実装にはいくつかの欠点があり、グループ通信の複雑さのために多くの回避策が作成されていました。要するに、ずっと前に2つのモジュールであるべきだったものが、今そうなるということです。Tribesはレプリケーションモジュールからメッセージングの複雑さを取り除き、完全に独立した柔軟性の高いグループ通信モジュールとなります。

Tomcatでは、以前の modules/clustermodules/groupcom(Tribes) と modules/ha (レプリケーション) となりました。これにより、開発を進め、開発者が興味のないモジュールの詳細に時間を取られることなく、実際に取り組んでいる問題に集中できるようになります。通信とレプリケーションの両方が十分に複雑であり、それらを同じモジュールで開発しようとすると、ご存知の通り、クラスタになってしまうということです :)

Tribesは保証されたメッセージングを可能にし、多くの方法でカスタマイズできます。なぜこれが重要なのでしょうか?
開発者として、送信しているメッセージが目的地に到達していることを確認したいと思うでしょう。それだけでなく、メッセージが目的地に到達しなかった場合、Tribesの上のアプリケーションは、メッセージが送信されなかったこと、およびどのノードで失敗したかを通知されます。

なぜ別のメッセージングフレームワークなのか

私はコードの再利用の大ファンであり、もし他の誰かがすでにそれを行い、私や私が貢献しようとしているコミュニティが利用できるのであれば、それを開発しようとは夢にも思わないでしょう。
クラスタリングモジュールを改善するために調査を行った際、私は常にいくつかの障害に直面しました。
1. フレームワークの柔軟性が不十分だった
2. フレームワークのライセンスが、私やコミュニティが利用できないようなものだった
3. 必要な機能がいくつか不足していた
4. メッセージングは保証されていたが、フィードバックが報告されなかった
5. メッセージ配信のセマンティクスを実行時前に設定する必要があった
そしてリストは続く...

そこで、これらの問題や付随する他の問題に対処するためにTribesを考案しました。Tribesを設計するにあたり、既存のフレームワークがすでに提供していた柔軟性と配信セマンティクスを失わないようにしたいと考えました。目標は、他のフレームワークがすでに提供していたすべての機能を実行できるだけでなく、アプリケーション開発者により多くの柔軟性を提供するフレームワークを作成することでした。次のセクションでは、Tribesが提供する、または提供する予定の機能の概要を説明します。

機能概要

機能セットの概要を把握していただくために、ここにリストアップします。一部の機能はまだ完成しておらず、その場合はそのようにマークされています。

プラグイン可能なモジュール
Tribesはインターフェースを使用して構築されています。Tribesの一部であるモジュールやコンポーネントは、独自のTribes実装をカスタマイズするために交換することができます。

保証されたメッセージング
Tribesのデフォルト実装では、メッセージングにTCPまたはUDPを使用します。TCPには、すでに保証されたメッセージ配信とフロー制御が組み込まれています。Java TCPのパフォーマンスは、ロジックがスタックのさらに下で発生するため、Java/UDP/フロー制御/メッセージ保証の実装を上回ると考えています。必要に応じてTCPの代わりにUDP経由でメッセージを送信するために、UDPメッセージングが追加されました。以下に説明する同じ保証シナリオはUDP経由でも利用できますが、UDPメッセージが失われた場合は失敗と見なされます。
TribesはノンブロッキングIO操作とブロッキングIO操作の両方をサポートします。メッセージの送受信時に並列性を向上させるため、ノンブロッキングの使用が推奨設定です。NIOがまだ問題のあるプラットフォーム向けに、ブロッキング実装が利用可能です。

異なる保証レベル
メッセージが送信される際には、3つの異なる配信保証レベルがあります。

  1. IOベースの送信保証。 - 最速、最も信頼性が低い
    これは、メッセージがソケット送信バッファに送信され、受け入れられた場合に、Tribesがメッセージ転送を成功と見なすことを意味します。
    ブロッキングIOでは、これは socket.getOutputStream().write(msg) となります
    ノンブロッキングIOでは、これは socketChannel.write() となり、バッファのバイトバッファが空になった後、チャネルがまだ開いていることを確認するために socketChannel.read() が続きます。NIOを使用している場合、接続が「クローズ」されていると write() が成功してしまうため、read() が追加されました。
  2. ACKベース。 - 推奨、保証された配信
    リモートノードでメッセージが受信されると、ACKが送信者に戻され、メッセージが正常に受信されたことを示します。
  3. SYNC_ACKベース。 - 保証された配信、保証された処理、最も遅い
    リモートノードでメッセージが受信されると、そのノードはメッセージを処理し、メッセージが正常に処理された場合、メッセージが正常に受信および処理されたことを示すACKが送信者に戻されます。メッセージは受信されたが、処理に失敗した場合、ACK_FAILが送信者に戻されます。これは、アプリケーション開発者にとって非常に大きな価値をもたらす独自の機能です。ほとんどのフレームワークでは、メッセージが配信されたことを伝えますが、アプリケーション開発者は、リモートノードのアプリケーションによってメッセージが実際に適切に処理されたかどうかについて、ロジックを組み込む必要があります。設定されている場合、TribesはACK_FAILを受信すると例外をスローし、その例外をメッセージを処理しなかったメンバに関連付けます。

もちろん、さらに洗練された保証レベルを記述することもでき、それらのいくつかはドキュメントの後半で言及されます。注目すべきレベルの1つは、すべてのノードがメッセージを受信するまでリモートアプリケーションがメッセージを受信しない2フェーズコミットです。オールオアナッシングプロトコルに似ています。

メッセージごとの配信属性
おそらく、Tribesを他のグループ通信フレームワークから際立たせる機能でしょう。Tribesを使用すると、メッセージ転送がメッセージごとにどのような配信セマンティクスを持つべきかを決定して送信できます。つまり、メッセージはメッセージフレームワークが開始された後に固定された静的な設定に基づいて配信されるわけではありません。
この機能がいかに強力であるかを示す例として、簡単な例で説明してみましょう。10種類のメッセージを送信する必要があると想像してください。次の方法で送信できます

Message_1 - asynchronous and fast, no guarantee required, fire and forget
Message_2 - all-or-nothing, either all receivers get it, or none.
Message_3 - encrypted and SYNC_ACK based
Message_4 - asynchronous, SYNC_ACK and call back when the message is processed on the remote nodes
Message_5 - totally ordered, this message should be received in the same order on all nodes that have been
            send totally ordered
Message_6 - asynchronous and totally ordered
Message_7 - RPC message, send a message, wait for all remote nodes to reply before returning
Message_8 - RPC message, wait for the first reply
Message_9 - RPC message, asynchronous, don't wait for a reply, collect them via a callback
Message_10- sent to a member that is not part of this group

これまでの説明でお分かりのように、これらは単なる例です。メッセージごとに適用できる異なるセマンティクスの数はほぼ無限です。Tribesでは、メッセージに対して最大28種類の異なる設定を行い、どのフラグがメッセージにどのようなアクションをもたらすかをTribesに構成できます。
共有トランザクションキャッシュを想像してみてください。おそらく90%以上が読み取りであり、ダーティリードは完全に順序付けされず、可能な限り高速に配信されるべきです。しかし、一方のトランザクション書き込みは、キャッシュが破損しないように順序付けされている必要があります。Tribesを使用すると、書き込みメッセージは完全に順序付けて送信し、読み取りメッセージは最高のスループットを達成するために単に発射することができます。
この強力な機能がどのように使用できるかについては、おそらくもっと良い例があるでしょう。したがって、あなたの想像力と経験を使って、これがあなたのアプリケーションでどのように役立つかを考えてみてください。

インターセプターベースのメッセージ処理
Tribesは、カスタマイズ可能なインターセプタースタックを使用して、送受信されるメッセージを処理します。
それがどうした、どのフレームワークにもあるではないか!
はい、しかしTribesでは、インターセプターは実行時に送信されるメッセージごとの属性に基づいてメッセージに反応できます。つまり、メッセージを暗号化する暗号化インターセプターを追加した場合、このインターセプターがすべてのメッセージを暗号化するか、それともTribes上で実行されるアプリケーションによって決定される特定のメッセージのみを暗号化するかを決定できます。
これが、Tribesが一部のメッセージを完全に順序付けて送信し、他のメッセージは上記の例のようにファイア・アンド・フォーゲット方式で送信できる理由です。
利用可能なインターセプターの数は増え続けるでしょう。皆様からのあらゆる貢献を歓迎いたします。

スレッドレスインターセプタースタック インターセプターは、メッセージ操作を実行するために個別のスレッドを必要としません。
送信されるメッセージは、送信しているスレッドに便乗して、送信全体を通じて処理されます。例外は MessageDispatchInterceptor で、これはメッセージをキューに入れ、非同期メッセージ配信のために別のスレッドで送信します。受信されたメッセージは、receiver コンポーネント内のスレッドプールによって制御されます。
チャネルオブジェクトは、インターセプタースタックを通じて heartbeat() を送信し、タイムアウト、クリーンアップ、その他のイベントを許可することができます。
MessageDispatchInterceptor は、デフォルトで構成されている唯一のインターセプターです。

並列配信
Tribesはメッセージの並列配信をサポートします。これは、node_Aがnode_Bに3つのメッセージを並列に送信できることを意味します。この機能は、異なる配信セマンティクスを持つメッセージを送信する際に役立ちます。そうでない場合、Message_1が完全に順序付けられて送信された場合、Message_2はそのメッセージが完了するまで待つ必要があります。
NIOを通じて、Tribesは同じスレッド上で同時に複数のレシーバーにメッセージを送信することもできます。

サイレントメンバメッセージング
Tribesを使用すると、グループに属していないメンバにメッセージを送信できます。したがって、デフォルトでは、動的検出モジュールは現在、動的なノード検出にマルチキャストを使用することでローカルエリアネットワークに限定されていますが、広域ネットワーク経由でメッセージを送信できます。もちろん、メンバシップコンポーネントは将来的にWANメンバシップをサポートするように拡張される予定です。しかし、これは、残りのグループからメンバを隠し、彼らとのみ通信したい場合に非常に役立ちます

Tribesはどこで入手できますか

TribesはTomcatにモジュールとして同梱されており、Apache Tomcatリリースの一部として公開されています。