RabbitMQ 保证消息可靠性

消息确认机制逻辑

1、消息抵达MQ服务器,会触发ConfirmCallback这个方法.
2、消息从交换机抵达对应的队列,成功不会触发,失败了会触发ReturnCallback这个方法.
3、消费者消费了消息之后,需要执行签收动作,也就是使用 basicAck() 手动签收,之后这个消息会从服务器删掉。

在这里插入图片描述

修改配置

1、发送端确认回调 生产者到broker服务端 
# 消息抵达服务器 就会触发回调
spring.rabbitmq.publisher-confirms=true
2、发送端确认回调 exchange 到 queue 投递成功不会触发,失败才会触发
# 开启发送端消息抵达队列确认机制 exchange 到 queue
spring.rabbitmq.publisher-returns=true
# 如果消息抵达了队列 就会优先执行这个回调  以异步的模式
spring.rabbitmq.template.mandatory=true
3、消费端确认机制
# 开启手动确认
spring.rabbitmq.listener.simple.acknowledge-mode=manual

代码实现

@Slf4j
@Configuration
public class MyRabbitConfig {

    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 自定义序列化方式 将字节码换成json
     *
     * @return
     */
    @Bean
    public MessageConverter converter() {
        return new Jackson2JsonMessageConverter();
    }

    // MyRabbitConfig对象创建完成之后,执行这个方法
    // Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
    @PostConstruct
    public void initRabbit() {

        // 设置发送端确认回调 生产者到broker服务端
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 设置发送端确认回调 生产者到broker服务端
             * 只要消息抵达服务器 就会触发回调  spring.rabbitmq.publisher-confirms=true
             * @param correlationData 当前消息的唯一ID
             * @param ack 消息是否成功或失败 true/false
             * @param cause 失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                log.info("消息抵达服务端:confirm:correlationData:{}", correlationData);
                log.info("消息抵达服务端:confirm:ack:{}", ack);
                log.info("消息抵达服务端:confirm:cause:{}", cause);

            }
        });

        // 设置发送端确认回调 exchange 到 queue 投递成功不会触发,失败才会触发
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * 消息抵达队列触发回调 exchange 到 queue ,只有消息没有到达队列才会触发这个回调,类似失败回调
             * # 开启发送端消息抵达队列确认机制 exchange 到 queue
             * spring.rabbitmq.publisher-returns=true
             * # 如果消息抵达了队列 就会优先执行这个回调  以异步的模式
             * spring.rabbitmq.template.mandatory=true
             * @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:message:{}", message);
                log.info("失败的消息:returnedMessage:replyCode:{}", replyCode);
                log.info("失败的消息:returnedMessage:replyText:{}", replyText);
                log.info("失败的消息:returnedMessage:exchange:{}", exchange);
                log.info("失败的消息:returnedMessage:routingKey:{}", routingKey);
            }
        });
    }
}
         // 消费端确认机制 保证每一个消息被正确消费 此时才能broker删除这个消息
        // # 手动确认
        // spring.rabbitmq.listener.simple.acknowledge-mode=manual
        // 默认是自动确认的 消费端只要消息接收到,消费端会自动确认,服务端就会移除这个消息
        // 问题:收到很多消息,自动回复给服务器ACK 只有一个消息处理成功,服务宕机了,发生了消息丢失,原因是自动确认了
        // 手动确认:只要没有明确告诉MQ,消息没有被签收,没有ACK MQ就会一直存在 UACK状态,即使服务器宕机消息也不会丢失,会重新变为Ready状态,下次
        //         有新的消费者就会把消息发送给他,保证消费者消息不丢失。
        //         basicAck() 手动签收 业务成功完成
        //         basicNack() 拒签 业务失败 拒签


@RabbitHandler
public void processMessage2(String message,Channel channel,@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
    System.out.println(message);
    try {
        channel.basicAck(tag,false);            // 确认消息
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ 通过持久化和确认机制来保证消息可靠性。 在发送消息时,可以设置消息的 delivery mode 为 2,表示消息需要被持久化。持久化的消息会被写入磁盘,即使 RabbitMQ 服务器宕机或重启,消息也不会丢失。 在接收消息时,可以使用确认机制。当消费者成功处理了一条消息后,会向 RabbitMQ 发送确认消息。如果 RabbitMQ 收到确认消息,就会将该消息从队列中删除,否则该消息会被重新发送。通过确认机制,可以保证消息不会被重复消费。 以下是一个简单的 RabbitMQ 发送和接收消息的示例代码: ``` import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() # 声明队列 channel.queue_declare(queue='hello', durable=True) # 发送消息 channel.basic_publish(exchange='', routing_key='hello', body='Hello World!', properties=pika.BasicProperties(delivery_mode=2)) print(" [x] Sent 'Hello World!'") # 接收消息 def callback(ch, method, properties, body): print(" [x] Received %r" % body) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(queue='hello', on_message_callback=callback) print(' [*] Waiting for messages. To exit press CTRL+C') channel.start_consuming() ``` 在这个示例中,我们设置了队列的 durable 属性为 True,表示队列需要被持久化。在发送消息时,我们设置了消息的 delivery mode 为 2,表示消息需要被持久化。在接收消息时,我们使用了确认机制,通过调用 ch.basic_ack() 方法确认消息已经被消费

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值