1. はじめに
1.1. デッドレタースイッチとは
デッドレターとは何ですか?
キュー内のメッセージが次のいずれかの条件を満たす場合、デッドレターになる可能性があります。
-
コンシューマは、basic.reject または Basic.nack を使用して消費の失敗を宣言し、メッセージの requeue パラメータが false に設定されます。
-
メッセージは期限切れのメッセージです。タイムアウト後は誰も消費しません
-
配信するキューメッセージがいっぱいのため配信できません
デッド レターを含むキューがdead-letter-exchange
属性で構成され、スイッチが指定されている場合、キュー内のデッド レターはこのスイッチに配信され、このスイッチはデッド レター交換(Dead Letter Exchange、DLX を確認) と呼ばれます。
図に示すように、メッセージはコンシューマによって拒否され、デッドレターになります。
simple.queue はデッド レター交換 dl.direct にバインドされているため、デッド レターはこの交換に配信されます。
デッド レター スイッチもキューにバインドされている場合、メッセージは最終的にデッド レターが保存されているキューに入ります。
さらに、キューがデッド レターをデッド レター エクスチェンジに配信するとき、次の 2 つの情報を知っている必要があります。
-
デッドレタースイッチ名
-
デッドレター交換およびデッドレターキューにバインドされた RoutingKey
この方法によってのみ、配信されたメッセージがデッド レター交換に到達し、デッド レター キューに正しくルーティングされることが保証されます。
1.2. デッドレタースイッチを使用してデッドレターを受信する(拡張)
失敗の再試行戦略では、デフォルトの RejectAndDontRequeueRecoverer は、ローカル再試行回数を使い果たした後、RabbitMQ に拒否を送信し、メッセージはデッドレターになって破棄されます。
デッドレター スイッチを simple.queue に追加し、キューをデッドレター スイッチにバインドできます。このようにして、メッセージはデッド レターになった後も破棄されず、最終的にデッド レター エクスチェンジに配信され、デッド レター エクスチェンジにバインドされたキューにルーティングされます。
コンシューマ サービスでは、デッド レター スイッチとデッド レター キューのセットを定義します。
// 声明普通的 simple.queue队列,并且为其指定死信交换机:dl.direct
@Bean
public Queue simpleQueue2(){
return QueueBuilder.durable("simple.queue") // 指定队列名称,并持久化
.deadLetterExchange("dl.direct") // 指定死信交换机
.build();
}
// 声明死信交换机 dl.direct
@Bean
public DirectExchange dlExchange(){
return new DirectExchange("dl.direct", true, false);
}
// 声明存储死信的队列 dl.queue
@Bean
public Queue dlQueue(){
return new Queue("dl.queue", true);
}
// 将死信队列 与 死信交换机绑定
@Bean
public Binding dlBinding(){
return BindingBuilder.bind(dlQueue()).to(dlExchange()).with("simple");
}
1.3. 概要
どのようなメッセージがデッドレターになりますか?
-
メッセージがコンシューマによって拒否されるか、Nack が返されます。
-
メッセージがタイムアウトになり、消費されませんでした
-
キューがいっぱいです
デッドレター交換の使用シナリオは何ですか?
-
キューがデッド レター交換にバインドされている場合、デッド レターはデッド レター交換に配信されます。
-
デッド レター スイッチを使用すると、コンシューマが処理できなかったすべてのメッセージ (デッド レター) を収集し、手動処理に引き渡すことで、メッセージ キューの信頼性をさらに向上させることができます。
2、TTL
キュー内のメッセージがタイムアウト後に消費されない場合、そのメッセージはデッドレターになります。タイムアウトには 2 つのケースがあります。
-
メッセージが配置されているキューにはタイムアウトが設定されています
-
メッセージ自体がタイムアウトを設定します
2.1. タイムアウトデッドレターを受信するデッドレタースイッチ
コンシューマ サービスの SpringRabbitListener で、新しいコンシューマを定義し、デッド レター スイッチとデッド レター キューを宣言します。
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "dl.ttl.queue", durable = "true"),
exchange = @Exchange(name = "dl.ttl.direct"),
key = "ttl"
))
public void listenDlQueue(String msg){
log.info("接收到 dl.ttl.queue的延迟消息:{}", msg);
}
2.2. キューの宣言とTTLの指定
キューのタイムアウトを設定するには、キューを宣言するときに x-message-ttl 属性を構成する必要があります。
@Bean
public Queue ttlQueue(){
return QueueBuilder.durable("ttl.queue") // 指定队列名称,并持久化
.ttl(10000) // 设置队列的超时时间,10秒
.deadLetterExchange("dl.ttl.direct") // 指定死信交换机
.build();
}
このキューはデッドレター スイッチを次のように設定することに注意してください。dl.ttl.direct
スイッチを宣言し、ttl をスイッチにバインドします。
@Bean
public DirectExchange ttlExchange(){
return new DirectExchange("ttl.direct");
}
@Bean
public Binding ttlBinding(){
return BindingBuilder.bind(ttlQueue()).to(ttlExchange()).with("ttl");
}
メッセージを送信しますが、TTL は指定しません。
@Test
public void testTTLQueue() {
// 创建消息
String message = "hello, ttl queue";
// 消息ID,需要封装到CorrelationData中
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
// 发送消息
rabbitTemplate.convertAndSend("ttl.direct", "ttl", message, correlationData);
// 记录日志
log.debug("发送消息成功");
}
送信メッセージのログ:
受信したメッセージのログを表示します。
キューの TTL 値は 10000ms、つまり 10 秒であるためです。メッセージの送信と受信の時間差がちょうど 10 秒であることがわかります。
2.3. メッセージ送信時にTTLを設定する
メッセージを送信するときに、TTL を指定することもできます。
@Test
public void testTTLMsg() {
// 创建消息
Message message = MessageBuilder
.withBody("hello, ttl message".getBytes(StandardCharsets.UTF_8))
.setExpiration("5000")
.build();
// 消息ID,需要封装到CorrelationData中
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
// 发送消息
rabbitTemplate.convertAndSend("ttl.direct", "ttl", message, correlationData);
log.debug("发送消息成功");
}
送信されたメッセージのログを表示します。
メッセージログの受信:
今回は、送信と受信の間の遅延はわずか 5 秒でした。キューとメッセージの両方に TTL が設定されている場合、期限切れのものはデッドレターになることに注意してください。
2.4. 概要
メッセージのタイムアウトには 2 つの方法がありますか?
-
キューに ttl 属性を設定すると、キューに入った後に ttl 時間を超えたメッセージはデッドレターになります
-
メッセージに ttl 属性を設定すると、ttl 時間を超えてメッセージを受信するとキューはデッドレターになります。
消費者がメッセージを送信してから 20 秒後にメッセージを受信したことをどのように認識すればよいでしょうか?
-
メッセージの宛先キューのデッドレター交換を指定します
-
コンシューマがリッスンするキューをデッドレター交換にバインドします
-
メッセージを送信するときは、メッセージのタイムアウト時間を 20 秒に設定します。
3. 遅延キュー
TTL とデッドレター スイッチを組み合わせて使用することで、コンシューマがメッセージの送信後に受信を遅らせる効果が得られました。このメッセージモードを遅延キュー(Delay Queue)モードと呼びます。
遅延キューの使用例には次のものがあります。
-
SMS送信の遅延
-
ユーザーが注文し、15分以内に支払いがない場合、注文は自動的にキャンセルされます
-
仕事の会議をスケジュールし、20 分後にすべての参加者に自動的に通知します
遅延キューに対する需要が非常に多いため、RabbitMQ は遅延キュー効果をネイティブにサポートするプラグインを正式にリリースしました。
このプラグインは DelayExchange プラグインです。RabbitMQ のプラグイン リスト ページを参照してください: Community Plugins — RabbitMQ
使用方法については、公式 Web サイトのアドレスを参照してください: RabbitMQ でメッセージをスケジュールする | RabbitMQ - Blog
3.1. DelayExchange プラグインのインストール
MQ をインストールする
次のコマンドを実行して MQ コンテナを実行します。
docker run \ -e RABBITMQ_DEFAULT_USER=itcast \ -e RABBITMQ_DEFAULT_PASS=123321 \ -v mq-plugins:/plugins \ --name mq \ --hostname mq1 \ -p 15672:15672 \ -p 5672:5672 \ -d \ rabbitmq:3.8-management
DelayExchangeプラグインをインストールする
公式インストール ガイドのアドレスは次のとおりです: RabbitMQ を使用したメッセージのスケジュール | RabbitMQ - ブログ
上記のドキュメントは、RabbitMQ を Linux にネイティブにインストールし、その後プラグインをインストールすることに基づいています。
以前にDockerベースでRabbitMQをインストールしたので、今回はDockerベースでRabbitMQプラグインをインストールする方法を説明します。
プラグインをダウンロード
RabbitMQ には、次の場所に公式プラグイン コミュニティがあります: Community Plugins — RabbitMQ
これには、これから使用する DelayExchange プラグインを含む、さまざまなプラグインが含まれています。
対応する GitHub ページに移動して、プラグインの 3.8.9 バージョンをダウンロードできます。アドレスは、リリース v3.8.9 Rabbitmq/rabbitmq-layed-message-exchange GitHubです。これは、RabbitMQ バージョン 3.8.5 以降に対応します。
プラグインをアップロードする
Dockerベースでインストールしているため、最初にRabbitMQプラグインディレクトリに相当するデータ量を確認する必要があります。Docker ベースでない場合は、Docker コンテナを再作成します。
前に設定した RabbitMQ のデータ ボリューム名は である
mq-plugins
ため、次のコマンドを使用してデータ ボリュームを表示します。docker volume inspect mq-plugins
次の結果が得られます。
次に、プラグインをこのディレクトリにアップロードします。
プラグインをインストールする
最後にインストールされますが、インストールを実行するには MQ コンテナ内に入る必要があります。私のコンテナの名前は なので
mq
、次のコマンドを実行します。docker exec -it mq bash
実行する際
-it
はmq
以下を自分のコンテナ名に置き換えてください。コンテナに入ったら、次のコマンドを実行してプラグインを有効にします。
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
3.2. DelayExchangeの原理
DelayExchange では、交換が遅延していると宣言される必要があります。lateExchange にメッセージを送信するときのフローは次のとおりです。
-
メッセージを受信する
-
メッセージに x-delay 属性があるかどうかを判断する
-
x-lay 属性がある場合、それはハード ディスクに永続化される遅延メッセージであることを意味し、x-lay 値が遅延時間として読み取られます。
-
ルーティングが見つからないという結果をメッセージ送信者に返します
-
x 遅延時間が経過した後、指定されたキューにメッセージを再配信します。
3.3. DelayExchange の使用
プラグインの使用も非常に簡単です。スイッチを宣言します。スイッチのタイプは任意で、遅延属性を true に設定し、それをバインドするキューを宣言するだけです。
1) DelayExchange スイッチを宣言します
注釈ベース (推奨):
@Bean に基づくこともできます。
2) メッセージを送信する
メッセージを送信するときは、遅延時間を指定するために x-delay 属性を必ず指定してください。
3.4. 概要
遅延キュープラグインを使用する手順は何ですか?
• スイッチを宣言し、delayed 属性を true に追加します。
• メッセージを送信するときに、x-lay ヘッダーを追加します。値はタイムアウト時間です。