RabbitMQ的死信队列

1、死信队列

1.1、DeadLetter: 是RabbitMQ中的一种消息机制

出现死信消息的可能情况如下

  1. 消息被否定确认,channel.basicNack 或 channel.basicReject, requeue=false
  2. 消息在队列的存活时间超过设置的TTL时间
  3. 消息队列的消息总数已经超过最大的队列长度
1.2、 Dead Letter Pattern 死信模式

当消费者不能处理接收到的消息时候, 将这个消息重新发布到另一个队列中,这个过程中的Exchange称为死信交换机(DLX)、Queue就是死信队列

1.3、死信队列处理流程
  1. 死信消息实际上就是来设置队列的属性(配置死信队列
  2. 队列中若有死信消息,RabbitMQ会自动将这个消息重新发布到设置的Exchange上,进而路由到另外一个队列。
  3. 监听这个队列中的消息做处理(处理死信队列
1.4、配置死信队列
  1. 配置业务队列,绑定到业务交换机上
  2. 为业务队列配置死信交换机和路由key
  3. 为死信交换机配置死信队列
1.5、死信交换机的声明周期
  1. 业务消息被投入业务队列
  2. 消费者消费业务队列的消息,由于处理过程中发生异常,于是进行了nck或者reject操作
  3. 被nck或reject的消息由RabbitMQ投递到死信交换机中
  4. 死信交换机将消息投入相应的死信队列
  5. 死信队列的消费者消费死信消息

2、实例代码(boot-rabbit)

2.1、pom.xml


 
 org.springframework.boot
 spring-boot-starter-amqp
 
 
 org.springframework.boot
 spring-boot-starter-web
 
 
 org.springframework.boot
 spring-boot-starter-test
 test
 
 
 org.springframework.amqp
 spring-rabbit-test
 test
 

2.2、application.properties

spring.application.name=springboot-rabbitmq
server.port=8080
#默认地址就是127.0.0.1:5672,如果是服务器的rabbitmq就改下
spring.rabbitmq.host=192.168.174.130
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.listener.type=simple
#设置为false,会丢弃消息或者重新发步到死信队列
spring.rabbitmq.listener.simple.default-requeue-rejected=false
#手动签收
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#虚拟主机目录
spring.rabbitmq.virtual-host=/

2.3、RabbitMQConfig

@Configuration
public class RabbitMQconfig {
 /**
 * //业务Exchange
 */ public static final String BUSINESS_EXCHANGE_NAME="dead.letter.demo.simple.business.exchange";
 /**
 *    //两个业务队列
 */
 public static final String BUSINESS_QUEUEA_NAME="dead.letter.demo.simple.business.queuea";
 public static final String BUSINESS_QUEUEB_NAME="dead.letter.demo.simple.business.queueb";
 /**
 * 死信Exchange
 */ public static final String DEAD_LETTER_EXCHANGE="dead.letter.demo.simple.deadletter.exchange";
 /**
 * 路由key
 */ public static final String DEAD_LETTER_QUEUEA_ROUTING_KEY="dead.letter.demo.simple.deadletter.queuea";
 public static final String DEAD_LETTER_QUEUEB_ROUTING_KEY="dead.letter.demo.simple.deadletter.queueb";
 /**
 * 两个死信队列
 */
 public static final String DEAD_LETTER_QUEUEA_NAME="dead.letter.demo.simple.deadletter.queuea";
 public static final String DEAD_LETTER_QUEUEB_NAME="dead.letter.demo.simple.deadletter.queueb";
 /**
 * 声明业务Exchange
 */ @Bean("businessExchange")
 public FanoutExchange businessExchange(){
 //广播模式
 return  new FanoutExchange((BUSINESS_EXCHANGE_NAME));
 }
 /**
 * 声明死信Exchange
 */ @Bean("deadLetterExchange")
 public DirectExchange deadLetterExchange(){
 //点对点模式模式
 return  new DirectExchange((DEAD_LETTER_EXCHANGE));
 }
 /**
 * 声明业务队列A
 * @return
 */
 @Bean("businessQueueA")
 public Queue businessQueueA(){
 HashMap map = new HashMap<>(2);
 map.put("x-dead-letter-exchange",DEAD_LETTER_EXCHANGE);
 map.put("x-dead-letter-routing-key",DEAD_LETTER_QUEUEA_ROUTING_KEY);
 return QueueBuilder.durable(BUSINESS_QUEUEA_NAME).withArguments(map).build();
 }
 /**
 * 声明业务队列B
 * @return
 */
 @Bean("businessQueueB")
 public Queue businessQueueB(){
 HashMap map = new HashMap<>(2);
 map.put("x-dead-letter-exchange",DEAD_LETTER_EXCHANGE);
 map.put("x-dead-letter-routing-key",DEAD_LETTER_QUEUEB_ROUTING_KEY);
 return QueueBuilder.durable(BUSINESS_QUEUEB_NAME).withArguments(map).build();
 }
 /**
 * 声明死信队列A
 */ @Bean("deadLetterQueueA")
 public Queue deadLetterQueueA(){
 return  new Queue(DEAD_LETTER_QUEUEA_NAME);
 }
 /**
 * 声明死信队列B
 */ @Bean("deadLetterQueueB")
 public Queue deadLetterQueueB(){
 return  new Queue(DEAD_LETTER_QUEUEB_NAME);
 }
 /**
 * 声明业务队列A绑定关系
 */
 @Bean
 public Binding businessBindingA(@Qualifier("businessQueueA") Queue queue,
 @Qualifier("businessExchange")FanoutExchange exchange){
 return BindingBuilder.bind(queue).to(exchange);
 }
 /**
 * 声明业务队列B绑定关系
 */
 @Bean
 public Binding businessBindingB(@Qualifier("businessQueueB") Queue queue,
 @Qualifier("businessExchange")FanoutExchange exchange){
 return BindingBuilder.bind(queue).to(exchange);
 }
 /**
 * 声明死信队列A绑定关系
 */
 @Bean
 public Binding deadLetterBindingA(@Qualifier("deadLetterQueueA")Queue queue,
 @Qualifier("deadLetterExchange")DirectExchange exchange)   {
 return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEA_ROUTING_KEY);
 }
 /**
 * 声明死信队列B绑定关系
 */
 @Bean
 public Binding deadLetterBindingB(@Qualifier("deadLetterQueueB")Queue queue,
 @Qualifier("deadLetterExchange")DirectExchange exchange)   {
 return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEB_ROUTING_KEY);
 }
}

2.4、controller(MQ生产者)

@RestController
public class SendMessageController {
 @Autowired
 private RabbitMQconfig rabbitMQconfig;
 @Autowired
 private RabbitTemplate rabbitTemplate;
 public static final String BUSINESS_EXCHANGE_NAME="dead.letter.demo.simple.business.exchange";
 @GetMapping("/sendMsg")
 public String sendMsg(String msg){
 System.out.println("msg{}"+msg);
 rabbitTemplate.convertAndSend(BUSINESS_EXCHANGE_NAME,"",msg);
 return "success";
 }
}

2.5、业务消息消费者

@Component
public class BusinessMessageReceiver {
 /**
 *    //两个业务队列
 */
 public static final String BUSINESS_QUEUEA_NAME="dead.letter.demo.simple.business.queuea";
 public static final String BUSINESS_QUEUEB_NAME="dead.letter.demo.simple.business.queueb";
 /**
 * 消费消息
 */
 @RabbitListener(queues = BUSINESS_QUEUEA_NAME)
 public void receiveA(Message message, Channel channel) throws IOException {
 String msg=new String(message.getBody());
 System.out.println("BusinessMessageA{}"+msg);
 boolean ack=true;
 Exception exception=null;
 try {
 if (msg.contains("deadletter")){
 throw new RuntimeException("dead letter exception");
 }
 } catch (RuntimeException e) {
 ack=false;
 exception=e;
 }
 if (!ack){
 System.out.println("error msg{ }"+exception.getMessage());
 //设置死信消息
 channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
 }else {
 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
 }
 }
 /**
 * 消息信息B
 */ @RabbitListener(queues = BUSINESS_QUEUEB_NAME)
 public void receiveB(Message message,Channel channel) throws IOException {
 String msg = new String(message.getBody());
 System.out.println("BusinessMessageB{ }"+msg);
 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
 }
}

2.6、死信消息消费者

@Component
public class DeadMessageReceiver {
 /**
 * 两个死信队列
 */
 public static final String DEAD_LETTER_QUEUEA_NAME="dead.letter.demo.simple.deadletter.queuea";
 public static final String DEAD_LETTER_QUEUEB_NAME="dead.letter.demo.simple.deadletter.queueb";
 @RabbitListener(queues = DEAD_LETTER_QUEUEA_NAME)
 public void receiveA(Message message, Channel channel) throws IOException {
 System.out.println("DeadMessageA{}"+new String(message.getBody()));
 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
 }
 @RabbitListener(queues = DEAD_LETTER_QUEUEB_NAME)
 public void receiveB(Message message, Channel channel) throws IOException {
 System.out.println("DeadMessageB{}"+new String(message.getBody()));
 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
 }
}

你可能感兴趣的:(java,rabbitmq)