SpringBoot は RabbitMQ を統合します
1. オートモード(自動ACK)
RabbitMQ はデフォルトで auto モードになっており、監視コンシューマーメソッドが正常に実行されると、Spring は確認のために RabbitMQ に自動的に ack を返しますが、例外が発生した場合は消費失敗として RabbitMQ に nack を返します。
application.yml は RabbitMQ コンシューマ ACK 応答モードを構成します
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: auto
2 なしモード (ACK なし)
RabbitMQ はすべてのメッセージが正常に消費されると信じているため、RabbitMQ はメッセージを配信した後すぐにメッセージを削除します。
application.yml は RabbitMQ コンシューマ ACK 応答モードを構成します
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: none
3. マニュアルモード(マニュアルACK)
ビジネスを処理した後、開発者は RabbitMQ によってカプセル化された API を呼び出し、RabbitMQ に ack を返して消費の成功または失敗を確認します。
application.yml は RabbitMQ コンシューマ ACK 応答モードを構成します
spring:
rabbitmq:
listener:
simple:
# none(无应答模式) auto(自动应答模式) manual(手动应答模式)
acknowledge-mode: manual
4. コンシューマが再試行に失敗する
Spring 独自の自動再試行メカニズムを使用できます。コンシューマーで例外が発生した場合、メッセージをすぐにキューに戻してから RabbitMQ を再配信するのではなく、コンシューマー内でローカルに再試行します。これにより、CPU が急上昇します。(これにより、無限ループが発生します -> メッセージが異常になると、メッセージは継続的にキューに戻され、コンシューマーに再送信されます)。
application.yml 設定
キューとエクスチェンジを定義する
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RetryQueueConfig {
//定义direct类型交换机
@Bean
public DirectExchange retryExchange() {
return ExchangeBuilder.directExchange("retry.exchange").build();
}
//定义持久化队列
@Bean
public Queue retryQueue() {
return new Queue("retry.queue",true,false,false);
}
@Bean
public Binding retryQueueBinding(Queue retryQueue, DirectExchange retryExchange) {
return BindingBuilder.bind(retryQueue).to(retryExchange).with("retry");
}
}
模擬プロデューサー
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 RetryQueueTest {
@Autowired
private RabbitTemplate rabbitTemplate;
//模拟生产者
@Test
public void test(){
rabbitTemplate.convertAndSend("retry.exchange","retry","模拟消息异常");
}
}
コンソール出力
メッセージは 3 回の再試行後に削除されます
再試行失敗後の回復戦略
先ほどのローカルリトライでは、最大数に達するとメッセージが破棄されますが、これは Spring の内部メカニズムによって決定されます。
ただし、実際には、複数の消費を再試行しても失敗した後、SpringAMQP は、メッセージをさらに処理するために使用できるさまざまな回復戦略を定義する MessageRecoverer インターフェイスを提供します。
RejectAndDontRequeueRecoverer: 再試行が完了すると、直接拒否され、メッセージが失われます。デフォルトの処理戦略です
ImmediateRequeueMessageRecoverer: 再試行が完了すると、nack が返され、メッセージが再度キューに入れられます。
RepublishMessageRecoverer: 再試行が完了した後、指定された交換に失敗メッセージを配信します。
実際の開発では、より洗練されたソリューションは RepublishMessageRecoverer です。これは、失敗メッセージを例外メッセージの保存専用のキューに再ポストし、後続の手動処理を待ちます。
RepublishMessageRecoverer ポリシー コード
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RepublishMessageRecovererConfig {
/*
* 消息消费失败后的恢复策略:使用RepublishMessageRecoverer策略:重试次数耗尽后,将失败消息投递到指定的交换机
*/
@Bean
public MessageRecoverer republishMsgRecoverer(RabbitTemplate rabbitTemplate) {
return new RepublishMessageRecoverer(rabbitTemplate, "error.exchange", "error");
}
//定义Topic类型交换机
@Bean
public TopicExchange errorExchange() {
return ExchangeBuilder.topicExchange("error.exchange").build();
}
//定义队列
@Bean
public Queue errorQueue() {
return QueueBuilder.durable("error.queue").build();
}
//队列和交换机绑定
@Bean
public Binding errorQueueBinding(TopicExchange errorExchange, Queue errorQueue) {
return BindingBuilder.bind(errorQueue).to(errorExchange).with("error.#");
}
}
このようにして、例外メッセージの再試行が完了すると、例外メッセージは指定された例外キューに配信され、手動処理を待ちます。