7.RabbitMQ高级特性

本文详细探讨了如何通过RabbitMQ的发送端确认、消费端确认机制以及自身过期策略,确保消息在分布式系统中的可靠传递,包括同步与异步确认、消息路由与返回机制、限流与QoS,以及消息过期和死信队列的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

保证消息可靠性

消息的可靠性可以分为三个方面:

1.发送方:

需要使用RabbitMQ的发送端确认机制,确认消息成功发送到RabbitMQ并被处理

需要使用RabbitMQ的消息返回机制,若没有发现目标队列,中间件会通知发送方

 

2.消费方:

需要使用RabbitMQ的消费端确认机制,确认消息没有发生处理异常。

需要使用RabbitMQ的消费端限流机制,限制消息推送速度,确保接收端服务稳定

 

3.RabbitMQ自身:

大量堆积的消息会给RabbitMQ产生很大的压力,需要使用RabbitMQ消息过期时间,防止消息大量积压

消息过期后直接被丢弃,无法对系统运行异常发出警报,需要使用RabbitMQ的死信队列,收集过期消息,以供分析

 

1.发送端确认机制:

消息发送后,若中间件收到了消息,会给发送端一个应答。

确认机制有三种:

1.单条同步确认:

实现方法:

配置channel,开启确认模式:

channel.confirmSelect()

每发送一条消息,就调用channel.waitForConfirms()等待确认

2.多条同步确认:【不推荐】

实现方法:

配置channel,开启确认模式:channel.confirmSelect()

发送多条消息后,调用channel.waitForConfirms()等待确认

返回true:表示多条消息都签收成功

返回false:表示 发送的多条消息中有失败的,但不知道是哪一个,或者是哪几个失败了

3.异步确认:【不推荐】

实现方法:

配置channel,开启确认模式:channel.confirmSelect()

在channel上添加监听:addConfirmListener,发送消息后,会回调此方法,通知是否发送成功

异步确认有可能是单条,也可能是多条,取决于MQ

 

 

单条同步确认代码实现:

使用的是上一章节的订单微服务的创建订单接口


    public void createOrder(OrderCreateVO orderCreateVO) throws IOException, TimeoutException, InterruptedException {
        log.info("createOrder:orderCreateVO:{}", orderCreateVO);
        OrderDetailPO orderPO = new OrderDetailPO();
        orderPO.setAddress(orderCreateVO.getAddress());
        orderPO.setAccountId(orderCreateVO.getAccountId());
        orderPO.setProductId(orderCreateVO.getProductId());
        orderPO.setStatus(OrderStatus.ORDER_CREATING);
        orderPO.setDate(new Date());
        orderDetailDao.insert(orderPO);

        OrderMessageDTO orderMessageDTO = new OrderMessageDTO();
        orderMessageDTO.setOrderId(orderPO.getId());
        orderMessageDTO.setProductId(orderPO.getProductId());
        orderMessageDTO.setAccountId(orderCreateVO.getAccountId());

        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");

        try (Connection connection = connectionFactory.newConnection();
             Channel channel = connection.createChannel()) {
            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
            channel.confirmSelect();
            channel.addConfirmListener(new ConfirmListener() {
            if(channel.waitForConfirms()){
                log.info("confirm OK");
            }else {
               log.info("confirm Failed");
            }
           });

 

2.消息返回机制:

原理:消息发送后,中间件【exchange】会对消息进行路由,若没有发现目标队列,中间件会通知发送端,

Return Listener会被调用。可以在Return Listener中编写一些消息没有被路由的异常处理

 

消息返回的开启方法:

在RabbitMQ基础配置中有一个关键配置项:Mandatory

1.若Mandatory为 false,消息路由,找不到对应 的队列时,将会被直接丢弃。

2.若Mandatory为true,RabbitMQ才会处理无法路由的消息。

第三个参数就是设置 Mandatory 的

 channel.basicPublish("exchange.order.settlement", "key.settlement",true, null,
                                    messageToSend.getBytes());

Return Listener方法需要在消息发送前设置:

 


                channel.addReturnListener(new ReturnCallback() {
                    @Override
                    public void handle(Return returnMessage) {
                        log.info("Message Return: returnMessage{}", returnMessage);

                        //除了打印log,可以加别的业务操作
                    }
                });
                if (message.getEnvelope().getDeliveryTag()%10 == 0){
       

                String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                channel.basicPublish("exchange.order.restaurant", "key.order",true, null, messageToSend.getBytes());
                Thread.sleep(1000);

消息路由成功,该方法不会返回

 

3.消费端确认机制

默认情况下,消费端接收消息时,消息会被自动确认(ACK),这样mq就会认为消息被妥善发送了,当消费端消息处理异常时,发送端和消息中间件无法得知消息处理情况

需要使用RabbitMQ消费端确认机制,确认消息被正确处理。

消费端ACK类型:

1.自动ACK:消费端收到消息后,会自动签收消息

 

2.手动ACK:消费端收到消息后,不会自动签收消息,需要我们在业务代码中显示签收消息

手动ACK类型:

1.单挑手动ACK:multiple=false【推荐】

2.多条手动ACK:multiple=true【不推荐】

代码实现:

原先channel.basicConsume()监听函数,第二个参数就是设置是否自动的

 

4.消费端限流

业务高峰期,可能出现发送端和接收端性能不一致,大量消息被同时推送给接收端,造成接收端服务崩溃

需要使用RabbitMQ的消费端限流机制,限制消息推送速度,以保障接收端服务稳定

通过RabbitMQ-QoS【服务质量保障功能】保障限流

QoS功能保证了在一定数目的消息未被确认前,不消费新的消息。

Qos功能的前提是不使用自动确认

Qos原理:

当消费端有一定数量的消息未被ACK确认时,mq不会给消费端推送新的消息

mq使用QoS机制实现了消费端限流

消费端限流机制参数设置:

1.prefetchCount:针对一个消费端最多推送多少未确认的消息

 2.global:true 针对整个消费端限流; false:针对当前channel【是AMPQ协议中的,RabbitMQ暂未实现】

3.prefetchSize:0 (单个消息大小限制,一般为0)【是AMPQ协议中的,RabbitMQ暂未实现】

代码实现:

在消费者的channel.basicConsume()之上添加 channel.QoS(prefetchCount) ,剩余两个没有实现

===========================================

1.若mq没有实现QoS时,发送端有可能会将大量消息一下子都推给消费端,消费端所有的消息都处于Unack状态。消费端会一条一条的处理堆积的消息,处于Unack状态的消息不断减少。

但是当有大量消息堆积在一个消费端时,这时启动另一个消费端,这两个消费端都监听这个队列,但是没有对【有50条消息已经推给了第一个消费端的情况】没有任何改善,

因为50条消息已经推给了第一个消费端。另一个消费者是抢不到消息的。只能等第一个消费者将消息处理完,业务才能正常展开。

2.mq实现QoS时,这时启动第二个消费端,是能够改善情况的,因为堆积的消息处于Ready状态,第二个消费端是能够抢夺堆积的消息的

===========================================

 

5.消息过期机制

过期机制是为了解决队列爆满的。

默认情况下,消息进入队列,会永远存在,直到被消费

大量堆积的消息会给RabbitMQ产生很大的压力,

所以需要使用RabbitMQ的消息过期机制,防止消息大量堆积

RabbitMQ的过期时间(TTL【 Time to Live】):生存时间

RabbitMQ的过期时间分为:消息TTL  和 队列TTL

1.消息TTL : 设置了单条消息的过期时间

2.队列TTL:设置了队列中所有消息的过期时间【不是队列自己的过期时间】

TTL的设置主要考虑技术架构与业务:

1.TTL应该明显长于服务的平均重启时间

2.建议TTL 长于业务高峰期时间

单条消息的过期时间代码实现:

就是在发送消息时,给消息设置特殊参数

channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());

特殊参数原先是null

 

        
                //以毫秒为单位
                AMQP.BasicProperties properties=new   AMQP.BasicProperties().builder().expiration("15000").build();
                channel.basicPublish("exchange.order.restaurant", "key.order", properties, messageToSend.getBytes());

 

 

 

 

 

 

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值