RabbitMQ相关--消息可靠性投递

消息可靠性投递

在使用RabbitMQ时,消息生产者发送消息时会出现消息丢失或者投递失败的现象;

RabbitMQ在消息投递可靠性方面提供了两种模式:

1.Confirm 确认模式 producter->exchange

2.Return 退回模式 exchange->queue

一、RabbitMQ运作原理

image.png

二、Confirm确认模式介绍及实现

producer -> exchange

消息确认,生产者消息投递后,如果exchange收到消息,则会给生产者一个答应。

生产者接收应答,以确定消息成功发送到exchange。

1.修改配置文件,开启确认模式

spring:
  rabbitmq:
    publisher-confirm-type: correlated 
  • confirm-type有none、correlated、simple这三种类型
  • none:表示禁用发布确认模式,默认值,使用此模式之后,不管消息有没有发送到Broker都不会触发 ConfirmCallback回调。
  • correlated:表示消息成功到达Broker后触发ConfirmCalllBack回调
  • simple:simple模式下如果消息成功到达Broker后一样会触发

2.实现RabbitTemplate.ConfirmCallback接口,实现Confirm方法

@Configuration
public class RabbitConfig {
    @Autowired
    private CachingConnectionFactory connectionFactory;

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(converter());

        // 消息是否成功发送到Exchange
        /**
        * correlationData 消息唯一标识
        * ack 交换机是否接收成功标识
        * cause 失败原因
        **/
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                log.info("消息成功发送到Exchange");
            } else {
                //通过correlationData携带的id可定位哪条消息发送失败,做补发操作
                log.info("消息发送到Exchange失败, {}, cause: {}", correlationData, cause);
            }
        });
    }
}

3.生产者发送消息

/**
 * CorrelationData作为消息标识id,回调时需要用到
 * Dto为Json形式
 */
@Service
public class Producter {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ObjectMapper objectMapper;
    
    public void sendMessage(Dto Dto) throws JsonProcessingException {
        mailDto.setMsgId(RandomUtil.randomUUID());
        String msgJson = objectMapper.writeValueAsString(Dto);
        Message message = MessageBuilder
                .withBody(msgJson.getBytes())
                .setContentType(MessageProperties.CONTENT_TYPE_JSON)
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT) //消息持久化
                .build();
        CorrelationData correlationData = new CorrelationData(mailDto.getMsgId());
        rabbitTemplate.convertAndSend(RabbitConfig.MAIL_EXCHANGE_NAME,RabbitConfig.MAIL_ROUTING_KEY_NAME,message,correlationData);
    }
}

二、Return退回模式介绍和实现

exchange->queue
如果消息未能路由到目标队列则将触发回调 ReturnCallback

1.修改配置文件,开启return

rabbitmq:
  publisher-confirms: true
  publisher-returns: true

2.实现returnedMessage方法

/**
 * message 消息主体
 * replycode 返回code
 * replyText 返回信息
 * exchange 交换机
 * routingkey 路由key
 */
// 触发setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
rabbitTemplate.setMandatory(true);

// 消息是否从Exchange路由到Queue, 注意: 这是一个失败回调, 只有消息从Exchange路由到Queue失败才会回调这个方法
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
    log.info("消息从Exchange路由到Queue失败: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", exchange, routingKey, replyCode, replyText, message);
});

三、消费端ACK手动确认机制

消息确认三种模式:manual、none、auto

  • 手动确认manual:消费消息后需要根据消费情况返回一个回执,成功手动调用channel.basicAck()手动签收,失败则调用channel.basicNack()方法拒收,让MQ重新发送该消息
  • 自动确认 none:默认消费者正确处理所有请求。(不设置时默认方式)
  • 根据情况确认 auto:不太常用

1.修改配置文件,开启ACK手动确认

spring:
  rabbitmq:
    publisher-confirm-type: correlated
    listener:
      simple:
        acknowledge-mode: manual

没有确认,消息为Unack状态

image.png

2.消费者接收消息并手动确认消息


@Override
@RabbitListener(queues = {RabbitMQConfig.DIRECT_QUEUE})
public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
    /**
     * long deliveryTag 标识符
     * boolean multiple 是否批量处理
     */
    try{
        System.out.println("业务处理流程,成功则ACK");
        channel.basicAck(tag,true);
    }catch (Exception e){
        /**
         * long deliveryTag 标识符
         * boolean multiple 是否批量处理
         * boolean requeue 是否回到队列
         */
        System.out.println("业务处理流程,失败则NACK");
        channel.basicNack(tag,false,true);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值