SpringBoot は RabbitMQ を統合します
1. デッドレター
1. デッドレターとは何ですか
キュー内のメッセージが次のいずれかの条件を満たす場合、デッドレターになる可能性があります。
- メッセージ TTL の有効期限が切れました。
- キューが最大長に達しました (キューがいっぱいで、RabbitMQ にこれ以上データを追加できません)。
- メッセージは拒否され (basic.reject または Basic.nack)、メッセージは requeue=false に設定されます (再エンキューしません)。
デフォルトでは、デッドレターは直接破棄されます
2. 消費の失敗は形骸化する
再試行ポリシー:
- RejectAndDontRequeueRecoverer: 再試行が完了すると、直接拒否され、メッセージが失われます。デフォルトの処理戦略です
- ImmediateRequeueMessageRecoverer: 再試行が完了すると、nack が返され、メッセージが再度キューに入れられます。
- RepublishMessageRecoverer: 再試行が完了した後、指定された交換に失敗メッセージを配信します。
失敗の再試行戦略では、デフォルトの RejectAndDontRequeueRecoverer は、ローカル再試行回数を使い果たした後、RabbitMQ に拒否を送信し、メッセージはデッドレターになって破棄されます。(RepublishMessageRecoverer 戦略を使用する場合は、必ずオフにしてください。オフにしないと、メッセージが戦略にバインドされたキューにスローされる可能性があります)
デッドレター スイッチをキューに追加し、デッドレター キューをデッドレター スイッチにバインドできます。このようにして、メッセージはデッドレターになった後も破棄されず、最終的にデッドレター スイッチに配信され、デッドレター スイッチにバインドされたデッドレター キューにルーティングされます。
3. デッドレタースイッチとデッドレターキューを定義する
デッドレター スイッチとデッドレター キューも一般的なスイッチとキューであるため、次のように定義されます。
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//死信交换机和死信队列也是普通的交换机和队列
@Configuration
public class DeadQueueConfig {
//定义死信交换机
@Bean
public DirectExchange deadLetterExchange() {
return ExchangeBuilder.directExchange("dead.letter.exchange").build();
}
//定义死信队列
@Bean
public Queue deadLetterQueue() {
return new Queue("dead.letter.queue",true,false,false);
}
//交换机和队列绑定
@Bean
public Binding deadLetterQueueBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange) {
return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("dl");
}
}
4. デッドレタースイッチとキューをバインドする方法
デッドレター交換とデッドレターキューをバインドする
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class TestDeadQueueConfig {
@Bean
public DirectExchange testDeadLetterExchangeExchange() {
return ExchangeBuilder.directExchange("test.dead.letter.exchange").build();
}
@Bean
public Queue testDeadLetterQueue() {
return QueueBuilder.durable("test.dead.letter.queue")
//test.dead.letter.queue队列绑定死信交换机
.deadLetterExchange("dead.letter.exchange")
//死信交换机和死信队列绑定 routingKey = dl
.deadLetterRoutingKey("dl")
.build();
/*Map<String, Object> args = new HashMap();
// DLX(死信交换机)
args.put("x-dead-letter-exchange", "死信队列交换机的名称");
// DLK(死信路由key)
args.put("x-dead-letter-routing-key", "死信消息路由的routingKey");
// TTL(time-to-live存活时间)
args.put("x-message-ttl", 10000);
return new Queue("test.dead.letter.queue",true,false,false,args);*/
}
//交换机和队列绑定
@Bean
public Binding testDeadLetterQueueBinding(Queue testDeadLetterQueue, DirectExchange testDeadLetterExchangeExchange) {
return BindingBuilder.bind(testDeadLetterQueue).to(testDeadLetterExchangeExchange).with("test.dead.letter");
}
}
5. メッセージが失敗すると、デッドレターに配信されます。
模擬プロデューサー
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DeadQueueTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void test(){
//模拟生产者
rabbitTemplate.convertAndSend("test.dead.letter.exchange","test.dead.letter","进行死信测试");
}
}
模擬消費者
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class DeadQueueListener {
@RabbitListener(queues = "test.dead.letter.queue")
public void testDeadLetterQueueMsg(String msg){
System.out.println("test.dead.letter.queue收到消息:"+msg);
//模拟:处理消息中出现了异常
int i = 1/0;
System.out.println("消息处理完毕!");
}
}
メッセージは配信不能キューに正常に配信されました
6. メッセージがタイムアウトになり、デッドレターに配信される
デフォルトでは、メッセージは期限切れになりません。メッセージの期限切れに関連するパラメータを設定しない場合、メッセージは期限切れになりません。メッセージが消費されない場合でも、メッセージは常にキューに保存されます。
TTL が設定されている場合、メッセージはこの時間を超えると自動的に削除されます。
- キューのプロパティによって設定: キュー内のすべてのメッセージの有効期限が同じになります
- メッセージを個別に設定します: 各メッセージの TTL は異なる場合があります
- 両方の方法を同時に使用すると、有効期限は最小値に従います。
1. デッドレターキューに配信されるデモキュータイムアウトTTL
キューを定義し、有効期限を設定します。
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TTLQueueConfig {
@Bean
public DirectExchange ttlExchange(){
return ExchangeBuilder.directExchange("ttl.exchange").build();
}
//定时队列,设置过期时间,并且绑定死信交换机
@Bean
public Queue ttlQueue(){
return QueueBuilder.durable("ttl.queue")
//设置队列的超时时间为10s
.ttl(10*1000)
//给队列设置死信交换机,名称为dead.letter.exchange 设置投递死信时的RoutingKey为dl
.deadLetterExchange("dead.letter.exchange")
.deadLetterRoutingKey("dl")
.build();
}
@Bean
public Binding ttlBinding(Queue ttlQueue, DirectExchange ttlExchange){
return BindingBuilder.bind(ttlQueue).to(ttlExchange).with("test.ttl.queue");
}
}
模擬プロデューサー
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class TTLQueueTest {
@Autowired
private RabbitTemplate rabbitTemplate;
//模拟生产者
@Test
public void test(){
rabbitTemplate.convertAndSend("ttl.exchange","test.ttl.queue","这个队列10秒后过期,然后到死信队列");
}
}
サービス開始後
、プロデューサーを呼び出します
2. デモンストレーション メッセージ タイムアウト TTL、配信不能キューに配信される
テストキュータイムアウトによるキューとデッドレター交換
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalTime;
@SpringBootTest
public class TTLQueueTest {
@Autowired
private RabbitTemplate rabbitTemplate;
//模拟生产者
@Test
public void testTTLMessage() {
String msgStr = "消息TTL demo,发送时间是:" + LocalTime.now();
Message message = MessageBuilder
.withBody(msgStr.getBytes())
//设置消息TTL为5秒
.setExpiration("5000")
.build();
//发送消息时:
// 如果消息和队列都设置了TTL,则哪个TTL短,哪个生效
// 如果消息和队列只设置了一个TTL,则直接以设置的为准
rabbitTemplate.convertAndSend("ttl.exchange", "test.ttl.queue", message);
}
}
使用シナリオ: ユーザーが注文し、ユーザーが 15 分以内に支払いを行わない場合、注文は自動的にキャンセルされます。