RabbitMQラーニング-第4章公開公開購読購読購読

前回の記事では、作業キューの作成に気づきました。作業キューの背後にあるrabbitMQは、実際には各タスクメッセージを1つのコンシューマにのみ送信します。この記事では、メッセージを複数のコンシューマーにプッシュする方法を研究します。このモデルは、パブリッシュ/サブスクライブと呼ばれます。

このパターンを説明するために、簡単なロギングシステムを構築します。これにはプログラムの2つの部分が含まれます。最初の部分はログメッセージを送信することで、2番目の部分はそれらを受信して​​印刷します。

ロギングシステムでは、実行中のすべてのコンシューマプログラムがメッセージを受信できます。そこで、レシーバーを実行してログをディスクに書き込むと同時に、別のコンシューマーを実行してログメッセージを画面に出力します。

基本的に、すべてのコンシューマにログメッセージをプッシュします。

1.メッセージ交換

前回の記事では、キューにメッセージを送信し、キューからメッセージを取り出しました。次に、RabbitMQの完全なメッセージモデルを紹介しましょう。

以前の内容を簡単に確認してみましょう。

  • プロデューサーアプリケーションはメッセージを送信します。
  • メッセージキューは、メッセージの保存とキャッシュに使用されます。
  • コンシューマープログラムがメッセージを受信する

RabbitMQのメッセージ送信モデルの中心的な考え方は、プロデューサーがメッセージをメッセージキューに直接送信しないことです。実際、プロデューサーは自分のメッセージがどのキューにキャッシュされるかわかりません。

実際、プロデューサーはエクスチェンジにメッセージを送信できます(メッセージエクスチェンジ)。Exchangeは非常に単純な問題であり、一方の側でプロデューサーからメッセージを受信し、もう一方の側でメッセージキューにメッセージをプッシュします。Exchangeは、メッセージを受信したときに何をすべきかを知っている必要があります。このメッセージを指定されたメッセージキューにプッシュする必要がありますか?または、すべてのキューにメッセージをプッシュしますか?またはニュースを捨てますか?これらのルールは、交換タイプを使用して定義できます。

直接、トピック、ヘッダー、ファンアウトなど、いくつかの交換タイプがあります。ここでは、主に最後のファンアウトを見ていきます。ここでは、logsという名前のエクスチェンジを作成し、fanoutと入力します。

channel.exchangeDeclare( "logs"、 "fanout");

ファンアウト型の交換は非常に簡単です。それは、受信できるすべてのメッセージを、知っているすべてのキューにブロードキャストするということです。これがまさに私たちのロギングシステムに必要なものです。

リスト交換:

サーバーでrabbitmqctlコマンドを使用して、RabbitMQサーバー上のすべてのメッセージ交換をリストできます。

rabbitmqctl list_exchanges
Listing exchanges ...
        direct
amq.direct      direct
amq.fanout      fanout
amq.headers     headers
amq.match       headers
amq.rabbitmq.log        topic
amq.rabbitmq.trace      topic
amq.topic       topic
logs    fanout

このリストには、amp。*の形式でいくつかの交換があり、デフォルトの(名前のない)スイッチもあります。これらはデフォルトで作成されます。

名前のない交換:

前の記事では交換の関連知識を使用しませんでしたが、メッセージを送信することはできます。正常に送信できる理由は、デフォルトの交換を使用しているため、( "")を使用して識別しています。

channel.basicPublish("", "hello", null, message.getBytes());

最初のパラメーターは、取引所の名前です。空の文字列のシンボルは、デフォルトまたは名前のない交換を指します。メッセージは、routingKeyに従って指定されたメッセージキューにルーティングされます。

次に、メッセージを名前付き交換にプッシュします。

channel.basicPublish( "logs", "", null, message.getBytes());

2.一時キュー

前の記事では、指定した名前(helloとtask_queue)のメッセージキューを使用しました。対応するプロデューサーとコンシューマーが同じメッセージキュー名を使用することが重要です。

しかし、これは私たちのログシステムの場合ではなく、ログメッセージの一部だけでなく、すべてのログメッセージを受信することを望んでいます。過去の履歴ログに関係なく、現在のログメッセージを処理するだけで済みます。これを実現するには、次の2つの手順を実行する必要があります。

  • RabbitMQとの接続を確立するたびに、キューを更新して空にする必要があります。これを実現するために、ランダムな名前でキューを作成するか(ランダムネスは自分で定義できます)、またはサーバーに自動的にランダムキューを作成させることができます。
  • コンシューマが切断すると、キューは自動的に削除されます。

Javaクライアントを使用する場合、パラメーターなしでqueueDeclareメソッドを使用して、名前があり、排他的で、自動的に削除されるキューを作成します。

String queueName = channel.queueDeclare().getQueue();

これは、amq.gen-JzTY20BRgKO-HjmUJj0wLgのような形のランダムな名前のキューを取得するためのものです。

3.バインディング

ファンアウトタイプの交換とキューを作成しました。次に、取引所にメッセージをキューに送信させる必要があります。Exchangeとキューの関係はバインドと呼ばれます。

channel.queueBind(queueName, "logs", "");

今後、ログという名前のエクスチェンジは、キュー内のメッセージを忘れます。

バインディングリストを表示します。

rabbitmqctl list_bindingsコマンドを使用して、すべての既存のバインディングを表示します。

4.最終的な実現

ログメッセージを送信するプロデューサープログラムは、前のプログラムと大差ありません。最大の違いは、以前に名前が付けられなかったデフォルトの交換ではなく、名前付き交換にメッセージをプッシュすることです。メッセージを送信するときにroutingKeyを提供する必要がありますが、ファンアウトタイプの交換では無視できます。以下はプロデューサーのコードEmitLog.javaです。

import java.io.IOException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;

public class EmitLog {

    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] argv)
                  throws java.io.IOException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        //声明exchange名字以及类型
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        
        // getMessage的实现请见上篇博文
        String message = getMessage(argv);

        //指定exchange的名字
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");

        channel.close();
        connection.close();
    }
    //...
}

ご覧のとおり、接続を確立した後、交換を宣言しました。存在しない交換にメッセージをプッシュすることは禁止されているため、この手順が必要です。

交換の原因となるキューがない場合、メッセージは失われますが問題ありません。コンシューマが待機していない場合、これらのメッセージは安全に破棄されます。

ReceiveLogs.javaのコードは次のとおりです。

import java.io.IOException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;

public class ReceiveLogs {

    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] argv)
                  throws java.io.IOException,
                  java.lang.InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        //声明消息路由的名称和类型
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

        //声明一个随机消息队列
        String queueName = channel.queueDeclare().getQueue();
        
        //绑定消息队列和消息路由
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        QueueingConsumer consumer = new QueueingConsumer(channel);
        
        //启动一个消费者
        channel.basicConsume(queueName, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");
        }
    }
}
  • ファイルをコンパイルします。

javac -cp。:amqp-client-3.3.5.jar ReceiveLogs.java EmitLog.java

  • ログをファイルに保存します。

java -cp。:amqp-client-3.3.5.jar ReceiveLogs> logs_from_rabbit.log

  • 次に、ログファイルを確認します。

尾-10f logs_from_rabbit.log

  • ログメッセージを画面に出力します。

java -cp。:amqp-client-3.3.5.jar ReceiveLogs

プロデューサーを開始します:
java -cp .: Amqp-client-3.3.5.jar EmitLog

ReceiveLogsを実行しているときに、rabbitmqctl list_bindingsコマンドを使用して、RabbitMQで交換を表示します。

rabbitmqctl list_bindings
Listing bindings ...
        exchange        amq.gen-1Zuyn_44c8IWsdJWrI42Og  queue   amq.gen-1Zuyn_44c8IWsdJWrI42Og  []
        exchange        amq.gen-rSrGSPWLNTuq1dfXipPfAA  queue   amq.gen-rSrGSPWLNTuq1dfXipPfAA  []
        exchange        task_queue      queue   task_queue      []
logs    exchange        amq.gen-1Zuyn_44c8IWsdJWrI42Og  queue           []
logs    exchange        amq.gen-rSrGSPWLNTuq1dfXipPfAA  queue           []

要約:

1.取引所の名前とタイプをプロデューサとコンシューマチャネルで宣言します。

2.プロデューサーのチャネルで送信先の交換を指定します

3.コンシューマチャネルでランダムメッセージキューを宣言してキュー名を取得し、メッセージキューとメッセージルートをチャネルにバインドします。

元の記事を40件公開 賞賛を25件 100,000回以上の閲覧

おすすめ

転載: blog.csdn.net/yym373872996/article/details/105651914