詳細RabbitMQの(b)は5キューの種類とその実現

1.シンプルモード

PプロデューサーはQをキューにメッセージを送信し、消費者Cは、受信します。

コード例1.1

ポンポンファイル

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.6.0</version>
</dependency>

RabbitMQUtilツール

package util;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * RabbitMQ Util
 *
 * @author HarryZhang
 */
public class RabbitMQUtil {
    private static Connection connection;

    /**
     * getConnection
     *
     * @return Connection
     */
    public static Connection getConnection() {
        if (connection != null) {
            return connection;
        }
        ConnectionFactory factory = new ConnectionFactory();

        factory.setHost("127.0.0.1");//MQ ip address

        factory.setPort(5672);//port

        factory.setUsername("HarryZhang");//username

        factory.setPassword("123456");//password

        try {
            connection = factory.newConnection();
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

ニュースプロデューサー

import com.rabbitmq.client.Channel;
import util.RabbitMQUtil;

import java.io.IOException;

public class Producer {
    //队列名
    private static final String QUEUE_NAME="debugers_test";
    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMQUtil.getConnection().createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        String message="Hello HarryZhang";
        channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
        System.out.println("推送成功");
    }
}

消費者ニュース

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

import java.io.IOException;

public class Consumer {
    private static final String QUEUE_NAME="debugers_test";
    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMQUtil.getConnection().createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        DeliverCallback deliverCallback=(consumerTag, delivery) -> {
            String message=new String(delivery.getBody(),"utf-8");
            System.out.println("接收消息:"+message);
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
    }
}

2.ワークキュー(作業キュー)

プロデューサー、複数の消費者は、メッセージは、消費者を検索することができます。複数の消費者は唯一のキューです。

python-2

2.1ポーリング分布(ラウンドロビン)

利点の一つは、あなたが簡単にキュー並列作業を働かせることができるということです。我々はバックログの作業の多くを持っている場合は、我々はシステムに容易に拡張性を作り、労働者(消費者)を増やすことで、この問題を解決することができます。デフォルトでは、RabbitMQの使用ポーリング配布ポリシーは、シーケンス内の次の消費者へのいずれかでメッセージを1つずつ送る(関係なく、各タスクの期間の、など、と、今後の時間配分ではなく、1つのアロケーションのです)します。平均的な消費者は、メッセージの同じ数を取得します。

消費者

package worker;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv1 {
    private static final String QUEUE_NAME="debugers_test";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        DeliverCallback deliverCallback=(consumerTag, delivery) -> {
            String message=new String(delivery.getBody(),"utf-8");
            System.out.println(" [x] Received '" + message + "'");
            // 休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
    }
}

プロデューサー

package workerfair;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import util.RabbitMQUtil;

import java.io.IOException;
import java.util.concurrent.TimeoutException;


public class Producer {
    private static final String QUEUE_NAME="debugers_test";
    public static void main(String[] args) throws IOException, InterruptedException, TimeoutException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        for (int i = 0; i < 100; i++) {
            // 消息内容
            String message = "" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");

            Thread.sleep(i * 10);
        }
        channel.close();
        connection.close();
    }
}

2.2公平な配分(フェアディスパッチ)

差異(ハードウェア、ネットワーク上の理由)があり、消費者のニュース機能に対応することができる、我々は強力な処理能力を消費者がプロセスメッセージにメッセージ、弱い消費者より少ない処理能力を処理することを期待しています。よるbasicQos(perfetch)autoAck協力を得ることができます。

  • basicQos:設定サーバーが送信すると同時にperfetch、消費者に**(ここでは1)**メッセージ
  • autoAck:手動への自動応答。それが処理された後、手動でメッセージを送信します。

消費者

package workerfair;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv1 {
    private static final String QUEUE_NAME="debugers_test";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback=(consumerTag, delivery) -> {
            String message=new String(delivery.getBody(),"utf-8");
            System.out.println(" [x] Received '" + message + "'");
            // 休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                System.out.println("[x] Done");
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
            }
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { });
    }
}

注:公正な配分を使用し、あなたがして、手動応答モードに切り替え、自動返信ACKをオフにする必要があります。

購読発行3.(パブリッシュ/サブスクライブ)

IMG

メッセージプロデューサは、複数の消費者を獲得することができる送信します。プロデューサー、スイッチ、複数のキュー、複数の消費者。

注:直接、ファンアウト、トピック、ヘッダー:XはRabbitMQの中にスイッチを表し、スイッチは、4つのタイプがあります。ここではファンアウト型があります。この後の複数のスイッチの詳細。

3.1モードの機能

  • プロデューサー、複数のコンシューマ
  • 各顧客が独自のキューを持っています
  • 生産者は、直接(キューにメッセージを送信しますが、スイッチに送信されませんExchange
  • 各キューには、スイッチを結合します
  • スイッチを介して生産者にメッセージを送信する - >到着待ち行列 - >キャンセルメッセージコンシューマ複数によって実装することができます

コード例3.2

プロデューサー

package ps;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import util.RabbitMQUtil;

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        // 消息内容
        String message = "Hello World!";
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");
        //关闭通道连接
        channel.close();
        connection.close();
    }
}

注: この時点では、スイッチがキューにバインドされていない、送信メッセージは確かに失われます。自身がデータを保存することができないスイッチされ、ストアデータキュー

消費者

package ps;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv1 {
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    private final static String QUEUE_NAME="debugers_test_sms";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

package ps;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv2 {
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    private final static String QUEUE_NAME="debugers_test_email";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

結合関係キューとスイッチ

1563099102615

4.ルートモード(ルーティング)

プロデューサーは、その後、モニターを直接交換にメッセージを送信、キューおよびスイッチに結合した場合に、プロデューサが送信メッセージがルーティングキーを指定し、メッセージがキューのみを対応する同じキーに送信され、キーのルートがありますメッセージキューの消費支出。消費者がメッセージを受信するためにそれは選択的です。

4.1コード例

バインディング 

バインドは、( bindingキューとスイッチとの間の関係です。:あなたは、単にとして理解することができますスイッチからのニュースに興味を持ったキュー。

追加的に結合するために使用することができますroutingKeyパラメータを。しないでください、とbasicPublish混乱。

//绑定队列到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");

プロデューサー

package routing;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import util.RabbitMQUtil;

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_direct";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        // 消息内容
        String message = "Hello World!";
        //参数2为routingKey
        channel.basicPublish(EXCHANGE_NAME, "delete", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");
        //关闭通道连接
        channel.close();
        connection.close();
    }
}

消費者1

package routing;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv1 {
    private final static String EXCHANGE_NAME = "test_exchange_direct";
    private static final String QUEUE_NAME="debugers_test_sms";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "insert");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

消費者2

package routing;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv2 {
    private final static String EXCHANGE_NAME = "test_exchange_direct";
    private static final String QUEUE_NAME="debugers_test_email";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

5.テーマ(トピック)

モードルーティング上記ワイルドカードパターンはファジーマッチングの点で人気がルーティングキーに記載の完全一致(正確に送信しないメッセージに等しい)です。

トピックにメッセージを送ることがドットで区切られなければならない任意のrouting_key-と交換することができません(。)単語リスト。言葉は何もすることができますが、通常、彼らはメッセージに関連付けられた機能のいくつかを指定します。

効果的なルーティングキーのいくつかの例:stock.usd.nyse、nyse.vmw、quick.orange.rabbit。キーをルーティングすることは、最大255のバイトまで、任意の数の文字を含むことができます。

二つの重要なキーバインドがあります:(特別な特性を持つ。単語のセグメンテーション、文字ではありません)

  • *:あなたは言葉に置き換えることができます。
  • #:あなたは、ゼロ以上の単語を置き換えることができます。

コード例5.1

プロデューサー

package topic;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import util.RabbitMQUtil;

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_topic";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        // 消息内容
        String message = "Hello World!";
        //参数2为routingKey
        channel.basicPublish(EXCHANGE_NAME, "routeKey.a", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");
        //关闭通道连接
        channel.close();
        connection.close();
    }
}

 消費者1

package topic;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv1 {
    private final static String EXCHANGE_NAME = "test_exchange_topic";
    private static final String QUEUE_NAME="debugers_test_sms";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*.*");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

消費者2

package topic;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import util.RabbitMQUtil;

public class Recv2 {
    private final static String EXCHANGE_NAME = "test_exchange_topic";
    private static final String QUEUE_NAME="debugers_test_email";
    public static void main(String[] args) throws Exception {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routeKey.*");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "utf-8");
            System.out.println(" [x] Received '" + message + "'");
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        };
        //修改为手动应答,true为自动应答,false相反
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
        });
    }
}

6. 4種類の交換(交換)

5種類キューモードのフロントを超える導入が、実際には3つだけ、最初の簡単なキュー、第2の動作モードでは、残りの3つが一緒にバインドされているが、このセクションの我々の一つと呼ばれるスイッチ細部へのスイッチ。

交換はすなわち、4分割:直接、ファンアウト、話題とヘッダを。

それぞれ最初の3つのモードがルーティング、公開およびワイルドカードパターンモードを購読、スイッチにマッチヘッダは、加えて、AMQPメッセージヘッダではなくキーのルーティングを可能にする正確に同じヘッダと直接交換スイッチが、パフォーマンスははるかに悪いです従って、スイッチが実質的に使用されず、ここでは詳細には説明しません。

6.1ダイレクト

ルーティングキーが正確な一致した場合、そのメッセージは、適切なキューに配信されます。

6.2ファンアウト

メッセージは、ファンアウトスイッチに送信されると、それはすべて、この追加のスイッチ上のキューにメッセージを配信します。

6.3トピック

。「」ファジーモード結合セット、「*」は、単一の文字にマッチする区切り文字としてオペレータの意志;「」、 『#』演算子ブロックの概念には、キーの任意の部分に一致するものとみなされますあなたは、複数の文字を一致させることができます。

7.まとめ

5 RabbitMQのキューについて、実際には、実際の使用は、ほとんどの操作がより快適に、最後のテーマは、あいまい一致です。我々はキュー(最後の3つのキュー)に参加するようにスイッチを合計する必要がありますので、以下のように動作します:

リリース8元の記事 ウォンの賞賛0 ビュー7262

おすすめ

転載: blog.csdn.net/fedorafrog/article/details/104291733