RabbitMQ保证数据不丢失 开启confirm 开启手动ack 实际操作

RabbitMQ保证数据不丢失

1.概述

生产者到MQ

首先:需要解决生产者到MQ数据丢失的问题如:MQ端服务器挂了导致数据丢失
1.MQ开启持久化:持久化就是写到硬盘,这样就不会出现MQ服务器挂了数据丢失的问题

@Configuration
public class RabbitMQConfig {

    public static final String PRODUCER_QUEUE="producer";

    //声明队列
    @Bean
    public Queue queue(){
        return new Queue(PRODUCER_QUEUE,true);//第二个属性为true代表开启持久化
    }

    //演示:开启交换机持久化
    @Bean
    public Exchange exchange(){
        return ExchangeBuilder.directExchange("demo")
        .durable(true)//该属性为true代表开启持久化
        .build();
    }
}

2.MQ开启confirm
MQ开启持久化后,还会出现一个问题:如果在持久化的过程中服务器挂了怎么办,所以我们需要开启MQ的confirm功能,默认为关闭,confirm功能就是在MQ接收到消息并持久化完成后会执行的操作,需要自定义实现RabbitTemplate.ConfirmCallback。操作如下
1)配置文件中开启confirm

spring:
  rabbitmq:
    publisher-confirms: true #开启confirm机制

2)实现RabbitTemplate.ConfirmCallback,重写confirm方法,添加发送数据方法

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Component
public class CustomMessageSender implements RabbitTemplate.ConfirmCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String MESSAGE_CONFIRM_KEY="message_confirm_";

	//构造方法,为当前rabbitTemplete添加ConfirmCallback处理类
    public CustomMessageSender(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setConfirmCallback(this);
    }

    /**
     * 回调方法
     * @param correlationData 本次操作的唯一标识
     * @param ack 成功/失败标识
     * @param cause
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack){
            //持久化成功
            //删除临时存储空间的内容
            redisTemplate.delete(correlationData.getId());
            redisTemplate.delete(MESSAGE_CONFIRM_KEY+correlationData.getId());
        }else{
            //持久化失败
            //消息重新发送
            Map<String,String> entries = redisTemplate.opsForHash().entries(MESSAGE_CONFIRM_KEY + correlationData.getId());
            String exchange = entries.get("exchange");
            String routingKey = entries.get("routingKey");
            String message = entries.get("message");
            //重新发送
            rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
        }
    }

    //在发送数据的同时,先向redis存一份数据,等到将来confirm方法返回持久化成功后,再将redis数据删除,否则就重新发送
    //自定义消息发送发送
    public void sendMessage(String exchange,String routingKey,String message){

        //向存储空间中存放本次消息的内容
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());

        redisTemplate.boundValueOps(correlationData.getId()).set(message);

        Map<String,String> map = new HashMap<>();
        map.put("exchange",exchange);
        map.put("routingKey",routingKey);
        map.put("message",message);
        redisTemplate.opsForHash().putAll(MESSAGE_CONFIRM_KEY+correlationData.getId(),map);

    
        //发送消息
        rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
    }
}

MQ到消费者

消费者同样有数据在接收到但还没处理的图中消费者服务器挂了,就会出现问题,所以我们同样需要确认,而此次确认是消费者给MQ确认,就又需要开启Ack手动确认功能,默认为自动应答,也就是消费者接收到数据MQ就不管了,你服务器挂了也不关我MQ的事,所以需要切换手动确认。操作如下
1)添加配置文件

spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual #切换手动应答

2)消费端进行操作后手动Ack,MQ在接受到Ack前,数据会一直保存在MQ中,所以可能MQ端压力会大于之前,所以可以设置一下MQ最大接收数据量,避免无限接收数据导致MQ爆炸,引起所有服务爆炸。

//300表示MQ最多存300条数据
channel.basicQos(300);

余下手动Ack实现

import com.alibaba.fastjson.JSON;
import com.demo.config.RabbitMQConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class ConsumeListener {

    @RabbitListener(queues = RabbitMQConfig.PRODUCER_QUEUE)
    public void handlerMessage(Message message, Channel channel){

        //设置预抓取总数
        try {
            channel.basicQos(300);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //消费数据
        //dohandlerMessage为自定义操作
        boolean result = dohandlerMessage(message);

        if (result){
            //操作成功
            //向mq发送成功通知
            /**
             * deliveryTag: 消息的唯一标识
             * multiple:是否批量操作
             */
            try {
              channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else{
            //操作失败
            //返回失败通知
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用RabbitMQ可以采取以下几种方式来保证消息不丢失。首先,可以使用持久化机制,确保消息在RabbitMQ服务宕机后不会丢失。这可以通过将消息标记为持久化,以及确保队列和交换机也是持久化的来实现。\[1\]其次,可以使用RabbitMQ提供的ack机制,即手动确认消息的处理完成。通过关闭自动ack功能,并在代码中手动调用ack,可以确保消息在处理完之后再从内存中删除,避免消息丢失。\[2\]此外,还可以使用事务或confirm模式来保证消息的可靠性。通过在生产者将消息推送到RabbitMQ开启事务或confirm模式,可以确保消息到达Exchange,并且根据RoutingKey正确地到达对应的Queue中,从而避免消息丢失。\[3\]综上所述,通过持久化、手动确认和使用事务或confirm模式,可以有效地保证使用RabbitMQ时消息不丢失。 #### 引用[.reference_title] - *1* *3* [RabbitMQ 保证消息不丢失的几种手段](https://blog.csdn.net/zhiyikeji/article/details/130190175)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [如何保证 RabbitMQ 消息不丢失?](https://blog.csdn.net/m0_71777195/article/details/129682495)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值