JGroupsによる信頼性の高いメッセージング

1概要

JGroups は信頼性のあるメッセージ交換のためのJava APIです。それは提供する簡単なインターフェースを特徴とします:

  • TCPとUDPを含む柔軟なプロトコルスタック

  • 大きなメッセージの断片化と再組み立て

信頼性の高いユニキャストとマルチキャスト

  • 故障検知

  • フロー制御

**

他の多くの機能と同様に。

このチュートリアルでは、アプリケーション間で String メッセージを交換し、新しいアプリケーションがネットワークに参加するときに共有状態を提供するための単純なアプリケーションを作成します。

2セットアップ

2.1. Mavenの依存関係

pom.xml に単一の依存関係を追加する必要があります。

<dependency>
    <groupId>org.jgroups</groupId>
    <artifactId>jgroups</artifactId>
    <version>4.0.10.Final</version>
</dependency>

ライブラリの最新版はhttps://search.maven.org/classic/#search%7C1%7Cg%3A%22org.jgroups%22%20AND%20a%3A%22jgroups%22[Mavenで確認できます。中央。]

2.2. ネットワーキング

JGroupsはデフォルトで IPV6 を使おうとします。

当社のシステム構成によっては、アプリケーションが通信できなくなる可能性があります。

これを回避するには、ここでアプリケーションを実行するときに java.net.preferIPv4Stack true プロパティに設定します。

java -Djava.net.preferIPv4Stack=true com.baeldung.jgroups.JGroupsMessenger

3 Jチャンネル

JGroupsネットワークへの接続は JChannel. です。このチャネルはクラスタに参加し、メッセージとネットワークの状態に関する情報を送受信します。

3.1. チャンネルを作成する

設定ファイルへのパスで JChannel を作成します。ファイル名を省略すると、現在の作業ディレクトリで udp.xml が検索されます。

明示的に名前を付けた設定ファイルでチャンネルを作成します。

JChannel channel = new JChannel("src/main/resources/udp.xml");

JGroupの設定は非常に複雑になる可能性がありますが、ほとんどのアプリケーションではデフォルトのUDPおよびTCP設定で十分です。コードにUDPのファイルを含めたので、このチュートリアルで使用します。

トランスポートの設定に関する詳細はJGroupsマニュアルhttp://jgroups.org/manual4/index.html# transport protocols[ここ]を参照してください。

3.2. チャンネルを接続する

チャネルを作成したら、クラスタに参加する必要があります。 ** クラスタはメッセージを交換するノードのグループです。

クラスタに参加するには、クラスタ名が必要です。

channel.connect("Baeldung");

クラスタに参加しようとする最初のノードが存在しない場合は作成します。このプロセスは以下のとおりです。

3.3. チャンネルに名前を付ける

ノードは名前で識別されるため、ピアはダイレクトメッセージを送信し、だれがクラスタに出入りしているかに関する通知を受信できます。

JGroupsは自動的に名前を割り当てます、あるいは私たちは自分自身を設定することができます:

channel.name("user1");

ノードがいつクラスタに出入りするかを追跡するために、以下でこれらの名前を使用します。

3.4. チャンネルを閉じる

ピアが終了したという通知をタイムリーに受信したい場合は、チャネルのクリーンアップが不可欠です。

closeメソッドで JChannel を閉じます。

channel.close()

4クラスタビューの変更点

JChannelが作成されたら、クラスタ内のピアの状態を確認し、それらとメッセージを交換する準備が整いました。

  • JGroupsは View クラス内のクラスタ状態を維持します** 各チャネルは単一のネットワークの View を持ちます。ビューが変わると、それは viewAccepted() コールバックを介して配信されます。

このチュートリアルでは、アプリケーションに必要なすべてのインターフェースメソッドを実装する ReceiverAdaptor APIクラスを拡張します。

  • コールバックを実装するための推奨される方法です。**

あなたのアプリケーションに view Accepted を追加しましょう。

public void viewAccepted(View newView) {

    private View lastView;

    if (lastView == null) {
        System.out.println("Received initial view:");
        newView.forEach(System.out::println);
    } else {
        System.out.println("Received new view.");

        List<Address> newMembers = View.newMembers(lastView, newView);
        System.out.println("New members: ");
        newMembers.forEach(System.out::println);

        List<Address> exMembers = View.leftMembers(lastView, newView);
        System.out.println("Exited members:");
        exMembers.forEach(System.out::println);
    }
    lastView = newView;
}

View には、クラスターの各メンバーを表す Address オブジェクトの List が含まれています。 JGroupsは、あるビューを別のビューと比較するための便利なメソッドを提供します。これを使用して、クラスタの新規メンバーまたは終了したメンバーを検出します。

5メッセージを送信する

JGroupsのメッセージ処理は簡単です。 Message には、送信者と受信者に対応する byte 配列と Address オブジェクトが含まれます。

このチュートリアルでは、コマンドラインから読み込んだ Strings を使用していますが、アプリケーションが他のデータ型をどのように交換できるかを簡単に確認できます。

5.1. ブロードキャストメッセージ

Message は、宛先とバイト配列を使用して作成されます。 JChannel は送信者を設定します。ターゲットが null の場合、クラスタ全体がメッセージを受け取ります。

コマンドラインからテキストを受け取り、それをクラスタに送信します。

System.out.print("Enter a message: ");
String line = in.readLine().toLowerCase();
Message message = new Message(null, line.getBytes());
channel.send(message);

プログラムを複数回実行してこのメ​​ッセージを送信した場合(以下の__receive()メソッドを実装した後)、それらすべてが** 送信者を含めて受信します。

5.2. メッセージをブロックする

メッセージを見たくない場合は、そのためのプロパティを設定できます。

channel.setDiscardOwnMessages(true);

前のテストを実行すると、メッセージ送信者はブロードキャストメッセージを受信しません。

5.3. ダイレクトメッセージ

ダイレクトメッセージを送信するには有効な Address が必要です。ノードを名前で参照している場合、 Address を検索する方法が必要です。幸い、そのための View があります。

現在の View は常に JChannel から利用できます。

private Optional<address> getAddress(String name) {
    View view = channel.view();
    return view.getMembers().stream()
      .filter(address -> name.equals(address.toString()))
      .findAny();
}

Address の名前は、クラスの toString() メソッドを介して利用できます。そのため、クラスタメンバーの List で必要な名前を検索するだけです。

それで、私たちはコンソールから名前を受け入れて、関連する目的地を見つけて、そして直接のメッセージを送ることができます:

Address destination = null;
System.out.print("Enter a destination: ");
String destinationName = in.readLine().toLowerCase();
destination = getAddress(destinationName)
  .orElseThrow(() -> new Exception("Destination not found");
Message message = new Message(destination, "Hi there!");
channel.send(message);

6. メッセージを受信する

メッセージを送信することができます、今すぐ追加してみましょう

__ReceiverAdaptorの空のreceiveメソッドをオーバーライドします。

public void receive(Message message) {
    String line = Message received from: "
      + message.getSrc()
      + " to: " + message.getDest()
      + " -> " + message.getObject();
    System.out.println(line);
}

メッセージに String が含まれているので、 getObject() System.out に安全に渡すことができます。

7. 州の交換

ノードがネットワークに入ると、クラスタに関する状態情報を取得する必要があります。 JGroupsはこれのための状態転送メカニズムを提供します。

ノードがクラスタに参加すると、単に getState() が呼び出されます。クラスタは通常、グループ内の最も古いメンバ(コーディネータ)から状態を取得します。

ブロードキャストメッセージ数をアプリケーションに追加しましょう。新しいメンバ変数を追加して receive() の内側でインクリメントします。

private Integer messageCount = 0;

public void receive(Message message) {
    String line = "Message received from: "
      + message.getSrc()
      + " to: " + message.getDest()
      + " -> " + message.getObject();
    System.out.println(line);

    if (message.getDest() == null) {
        messageCount++;
        System.out.println("Message count: " + messageCount);
    }
}

直接メッセージを数えると各ノードの番号が異なるため、 null の宛先をチェックします。

次に、 ReceiverAdaptor でさらに2つのメソッドをオーバーライドします。

public void setState(InputStream input) {
    try {
        messageCount = Util.objectFromStream(new DataInputStream(input));
    } catch (Exception e) {
        System.out.println("Error deserialing state!");
    }
    System.out.println(messageCount + " is the current messagecount.");
}

public void getState(OutputStream output) throws Exception {
    Util.objectToStream(messageCount, new DataOutputStream(output));
}

メッセージと同様に、JGroupsは状態を bytes の配列として転送します。

JGroupsは、状態を書き込むための InputStream とコーディネータへの OutputStream を提供します。 APIは、データをシリアライズおよびデシリアライズするための便利なクラスを提供します。

プロダクションコードでは、状態情報へのアクセスはスレッドセーフでなければなりません。

最後に、クラスタに接続した後で、 getState() への呼び出しをスタートアップに追加します。

channel.connect(clusterName);
channel.getState(null, 0);

getState() は状態を要求する宛先とミリ秒単位のタイムアウトを受け入れます。 null destinationはコーディネータを示し、0はタイムアウトしないことを意味します。

このアプリを1対のノードで実行してブロードキャストメッセージを交換すると、メッセージ数が増えます。

それから、3番目のクライアントを追加するか、そのうちの1つを停止して起動すると、新しく接続されたノードが正しいメッセージ数を出力することがわかります。

8結論

このチュートリアルでは、JGroupを使用してメッセージを交換するためのアプリケーションを作成しました。このAPIを使用して、どのノードがクラスタに接続してクラスタから離脱したかを監視し、また、参加したときにクラスタ状態を新しいノードに転送しました。

コードサンプルは、いつものようにhttps://github.com/eugenp/tutorials/tree/master/jgroups[GitHubで利用可能]にあります。

前の投稿:Java並行処理インタビューの質問(回答)
次の投稿:JavaでJetty 9サーバを作成および設定する