RabbitMQ消息保障

生产端

confirm消息确认机制

生产端投递的消息一旦投递到RabbitMQ后,RabbitMQ就会发送一个确认消息给生产端。

confirm消息确认机制指 消息生产者确认消息是否正常到达Exchange

开启同步确认

channel.confirmSelect(); //启动确认模式



channel.basicPublish()//TODO 发送消息
channel.waitForConfirms() // 普通确认,只能单条确认
channel.waitForConfirmsOrDie(); //批量确认,只要有一条确认不成功直接抛异常

开启异步确认

channel.confirmSelect(); //启动确认模式

channel.addConfirmListener(new ConfirmListener() {
    //消息正确到达broker
    @Override
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("已收到消息");
        //做一些其他处理
    }

    //RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack消息
    @Override
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("未确认消息,标识:" + deliveryTag);
        //做一些其他处理,比如消息重发等
    }
});

Return消息确认机制

Return消息确认机制指 消息生产者确认消息是否正常到达Queue

SPRING-AMQP

@Slf4j
@Component
public class RabbitmqService implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(String exchange,String routingKey,Object msg) {
        // 设置交换机处理失败消息的模式 true 表示消息由交换机 到达不了队列时,会将消息重新返回给生产者
        // 如果不设置这个指令,则交换机向队列推送消息失败后,不会触发 setReturnCallback
        rabbitTemplate.setMandatory(true);
        //开启confirm
        rabbitTemplate.setConfirmCallback(this);
        //开启return
        rabbitTemplate.setReturnCallback(this);
        //发送消息
        rabbitTemplate.convertAndSend(exchange,routingKey,msg);
    }

    /**
     *  参数三:true  表示如果消息无法正常投递,则return给生产者 ;false 表示直接丢弃
     * @param message   消息对象
     * @param replyCode 错误码
     * @param replyText 错误信息
     * @param exchange 交换机
     * @param routingKey 路由键
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.info("---- returnedMessage ----replyCode="+replyCode+" replyText="+replyText+" ");
    }

    /**
     * 消息生产者发送消息至交换机时触发,用于判断交换机是否成功收到消息
     * @param correlationData  相关配置信息
     * @param ack exchange 交换机,判断交换机是否成功收到消息    true 表示交换机收到
     * @param cause  失败原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if(ack){
            // 交换机接收到
            // TODO
        }else{
            // 没有接收到
            // TODO
        }
    }
}

RabbitMQ层

消息持久化

RabbitMQ收到消息后将这个消息暂时存在了内存,如果RabbitMQ宕机,那重启后数据就会丢失。

所以相关的数据应该持久化到硬盘中,RabbitMQ重启后也可以到硬盘 中取数据恢复。

RabbitMQ 模型

对Exchange Queue Message进行持久化

//第三个参数true表示这个exchange持久化
channel.exchangeDeclare(EXCHANGE_NAME, "direct",true);  

//声明Queue时 第二个参数持久化
channel.queueDeclare(QUEUE_NAME, false, false, false, null); 
// Spring-AMQP 在实例化 exchange和queue时进行声明 

//  MessageProperties.PERSISTENT_TEXT_PLAIN 消息持久化
 channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes(StandardCharsets.UTF_8)); 

                 

消息入库

如果RabbitMQ收到消息还没来得及将消息持久化到硬盘时,RabbitMQ宕机,这样消息还是丢失。

或者RabbitMQ在发送确认消息给生产端的过程中,由于网络故障而导致生产端没有收到确认消息,这样生产端就不知道RabbitMQ到底有没有收到消息,就不好做接下来的处理。

消息入库,顾名思义就是将要发送的消息保存到数据库中。

首先发送消息前先将消息保存到数据库中。

设立状态字段status=0,表示生产端将消息发送给了RabbitMQ但还没收到确认;在生产端收到确认后将status设为1,表示RabbitMQ已收到消息。

这里有可能会出现上面说的两种情况,所以生产端这边开一个定时器,定时检索消息表,将status=0并且超过固定时间后(可能消息刚发出去还没来得及确认这边定时器刚好检索到这条status=0的消息,所以给个时间)还没收到确认的消息取出重发(第二种情况下这里会造成消息重复,消费者端要做幂等性),可能重发还会失败,所以可以做一个最大重发次数,超过就做另外的处理。

image.png

消费端

RabbitMQ 消费端通信 出现问题导致数据丢失。

消费端没处理数据时宕机导致数据丢失。

手动确认消息

将自动ack机制改为手动ack机制

消息确认模式 手工模式

spring.rabbitmq.listener.simple.acknowledge-mode=manual

 //消费成功,确认消息
channel.basicAck(deliverTag, true);
//nack返回false,出现异常并重新回到队列,重新消费
//注意:参数三若设置为true,会出现死循环
channel.basicNack(deliverTag, false, true); 

你可能感兴趣的:(RabbitMQ消息保障)