前言Work Queues的基本特性请看另一篇文章
https://editor.csdn.net/md/?articleId=119969813

概念

消息确认就是用来保证生产者在发送消息到mq的过程中防止消息丢失的一种机制。发送方发消息给接受方一旦接收方接到消息后通知发送方,如果发送方设置了持久化那么接受方会在消息成功持久化后在通知发送方。

生产者消息确认的策略

消息的确认做有很多法,其中包括单条确认、批量确认、异步确认等。

单条确认
它是一种同步确认发布的方式,也就是发布一个消息之后只有它被确认发布,后续的消息才能继续发布,waitForConfirmsOrDie(long)这个方法只有在消息被确认的时候才返回,如果在指定时间范围内这个消息没有被确认那么它将抛出异常。这种确认方式有一个最大的缺点就是:发布速度特别的慢,因为如果没有确认发布的消息就会阻塞所有后续消息的发布
批量确认
先发布一批消息然后一起确认可以极大地提高吞吐量,当然这种方式的缺点就是:当发生故障导致发布出现问题时,不知道是哪个消息出现问题了,所以重新发布时就会将这整批消息重新发送,但这样就会造成消息重复消费反而性能下降。该方案仍然是同步的,也一样阻塞消息的发布

异步确认:性价比最高,无论可靠性还是效率都是最高效的,它是利用回调函数来达到消息可靠性传递的,无论接收方接受成功还是接受失败都会通知发送方。下面就让我们来详细讲解异步确认是怎么实现的。

RabbitMq工作原理图

在这里插入图片描述

每一个颜色块之间都存在着消息的确认机制,我们大概分为两大类,发送方确认和消费方确认,其中发送方确认又分为生产者到交换器的确认和交换器到队列的确认。

接下来主要讨论消费方的确认

消费者消息确认的策略

消费者应答,发生在监听队列的消费者处理业务失败,如,发生了异常,不符合要求的数据……,这些场景我们就需要手动处理,比如重新发送或者丢弃。

我们知道ACK是默认是自动的,自动确认会在消息发送给消费者后立即确认,但存在丢失消息的可能,如果消费端消费逻辑抛出异常,假如你用回滚了也只是保证了数据的一致性,但是消息还是丢了,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。

消息应答模式有:
AcknowledgeMode.NONE:自动应答
AcknowledgeMode.AUTO:根据情况应答
AcknowledgeMode.MANUAL:手动应答
一般情况下我们都采用手动应答

spring.rabbitmq.listener.direct.acknowledge-mode=MANUAL

需要注意的 basicAck 方法需要传递两个参数

deliveryTag(唯一标识 ID):当一个消费者向 RabbitMQ 注册后,会建立起一个 Channel ,RabbitMQ 会用 basic.deliver 方法向消费者推送消息,这个方法携带了一个 delivery tag, 它代表了 RabbitMQ 向该 Channel 投递的这条消息的唯一标识 ID,是一个单调递增的正整数,delivery tag 的范围仅限于 Channel
multiple:为了减少网络流量,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息

basicNack方法需要传递三个参数

deliveryTag(唯一标识 ID):
multiple
requeue: true :重回队列,false :丢弃,我们在nack方法中一般设置 false,因为重发没有意义。

basicReject方法需要传递两个参数

deliveryTag(唯一标识 ID):上面已经解释了。
requeue:在reject方法里必须设置true。

还要说明一下,建议大家不要重发,重发后基本还是失败,因为出现问题一般都是异常导致的,出现异常的话,我的观点是丢弃这个消息,然后在catch里做补偿操作。

到此,可以进行测试。

RestController
public class AsyncConfirmController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
    @GetMapping("/async/{id}")
    public String AETest(@PathVariable Integer id) {
        Order order = new Order(id, "胖虎");
        rabbitTemplate.convertAndSend("confirm_exchange", "", order);
        return "成功";
    }
 
---------------------------------
 
@Configuration
public class AsyncConfirmListener {
 
    @Bean
    public Queue confirmQueue() {
        return new Queue("confirm_queue");
    }
 
    @Bean
    public FanoutExchange confirmExchange() {
        return new FanoutExchange("confirm_exchange");
    }
 
    //交换器绑定队列
    @Bean
    Binding bindingExchangeConfirm(Queue confirmQueue, FanoutExchange confirmExchange) {
        return BindingBuilder.bind(confirmQueue).to(confirmExchange);
    }
}

发布确认进阶篇

通过上面的列子我们探讨了,如何应对队列在发送消息给消费者的过程中出现了问题导致消费者无法消费的问题,那么生产者发送消息给交换机的过程中出现了问题,以及交换机发送消息给队列的过程中出现了问题,应该如何应对?
具体请看我的一下篇文章生产方发布确认
https://blog.csdn.net/qq_42872629/article/details/120123218?spm=1001.2014.3001.5501

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐