消息的可靠性(RabbitMQ)

消息可靠性问题

在消息队列,任何一个环节出问题都会导致消息的不可靠(消息丢失),如何确保消息的可靠性呢,需要考虑到其中的每个角色,生产者可靠性、MQ可靠性、消费者可靠性。

生产者可靠性

1、生产者重试

生产者发送消息时,出现了网络故障,导致与MQ的连接中断,所以需要设置重试机制进行多次重试,在SpringAMQP的重试机制是阻塞式重试,会出现当前线程阻塞问题,可能会导致性能下降。

2、生产者确认

RabbitMQ有两种消息确认机制

  • Publisher Confirm
    用于确认消息是否成功到达 Exchange(交换器),但不关心消息是否路由到队列。属于生产者与RabbitMQ 服务端之间的确认机制。解决的是 “消息是否成功发出” 的问题。
  • Publisher Return
    用于确认消息是否从 Exchange 成功路由到 Queue(队列)。当消息无法路由到任何队列时,RabbitMQ 会通过 ReturnCallback 将消息返回给生产者。解决的是 “消息是否被队列接收” 的问题。
    实现:
  • Publisher Confirm使用
    1)引入springamqp依赖之后,通过配置文件开启
    在这里插入图片描述
    publisher-confirm-type有三种模式可选:
  • none:关闭confirm机制
  • simple:同步阻塞等待MQ的回执
  • correlated:MQ异步回调返回回执
spring:
  rabbitmq:
    publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型
    publisher-returns: true # 开启publisher return机制

2)定义ConfirmCallback
在调用RabbitTemplate中的convertAndSend方法时,多传递一个参数:

@Test
    public void testConfimCallback(){
        //1、创建CorrelationData
        CorrelationData correlationData = new CorrelationData();
        correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            @Override
            public void onFailure(Throwable ex) {
                //1、异常处理逻辑
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                //接收回执信息ack或者nack
                if(result.isAck()){
                    //生产者发送消息成功

                }
                else{
                    //!result.isAck()即nack
                    //生产者发送消息失败
                    result.getReason();//失败原因
                }
            }
        });
        
        rabbitTemplate.convertAndSend("交换机","路由","message",correlationData);
    }
  • Publisher Return使用
@Configuration
public class MQConfig implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returnedMessage) {
                //逻辑处理
            }
        });
    }
}

MQ可靠性

MQ的消息默认都是保存内存当中,会存在两个问题:1、重启消息丢失;2、内存空间有限,消息积压导致MQ阻塞。

1、数据持久化

  • 交换机持久化
  • 队列持久化
  • 消息持久化

2、LazyQueue

在这里插入图片描述

消费者可靠性

1、确认机制

SpringAMQP帮我们实现了消息确认。并允许我们通过配置文件设置ACK处理方式,有三种模式:

  • none:不处理。即消息投递给消费者后立刻ack,消息会立刻从MQ删除。非常不安全,不建议使用
  • manual:手动模式。需要自己在业务代码中调用api,发送ack或reject,存在业务入侵,但更灵活
  • auto:自动模式。SpringAMQP利用AOP对我们的消息处理逻辑做了环绕增强,当业务正常执行时则自动返回ack. 当业务出现异常时,根据异常判断返回不同结果:
    • 如果是业务异常,会自动返回nack;
    • 如果是消息处理或校验异常,自动返回reject;
      在这里插入图片描述

    2、重试机制

     spring:
    rabbitmq:
      listener:
        simple:
          retry:
            enabled: true # 开启消费者失败重试
            initial-interval: 1000ms # 初识的失败等待时长为1秒
            multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-interval
            max-attempts: 3 # 最大重试次数
            stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
    

3、失败处理策略

在这里插入图片描述

@Configuration
@ConditionalOnProperty(prefix = "spring.rabbitmq.listener.simple.retry.enabled",havingValue = "true")
public class ErrorConfigMQ {

    @Bean
    public DirectExchange errorExchange(){
        return new DirectExchange("error.direct");
    }
    @Bean
    public Queue errorQueue(){
        return new Queue("error.queue");
    }
    @Bean
    public Binding errorBinding(DirectExchange errorExchange, Queue errorQueue){
        return BindingBuilder.bind(errorQueue).to(errorExchange).with("error");
    }

    @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate,"error.direct","error");
    }
}

4、业务幂等性

何为幂等性?
幂等是一个数学概念,用函数表达式来描述是这样的:f(x) = f(f(x)),例如求绝对值函数。
在程序开发中,则是指同一个业务,执行一次或多次对业务状态的影响是一致的。

  • 唯一消息ID
  • 业务判断

总结

通过保证生产者、MQ、消费者的可靠性,来保证消息的可靠性。

### RabbitMQ 消息可靠性配置及保障机制 RabbitMQ消息可靠性保障是一个多层次的过程,涉及生产者、中间件本身以及消费者三个方面的协同工作。以下是具体的方法和配置: #### 生产者的可靠性保障 为了确保生产者能够可靠地将消息发送到 RabbitMQ 中的交换机,可以采用以下措施: - **AMQP 协议支持**:通过 AMQP 协议实现可靠的网络传输,该协议提供了事务模式和发布确认功能来增强数据传递的安全性[^1]。 - **生产者确认机制 (Publisher Confirms)**:启用此功能后,当一条消息被成功写入磁盘并路由至至少一个队列时,Broker 将向生产者返回 ACK 响应;如果发生错误,则会收到 NACK 或超时提示[^4]。 ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 开启 publisher confirms channel.confirm_delivery() try: channel.basic_publish(exchange='my_exchange', routing_key='routing.key', body='Message content') except Exception as e: print(f"Failed to deliver message: {e}") finally: connection.close() ``` #### RabbitMQ 自身的消息持久化与恢复能力 即使在服务崩溃的情况下,也可以依靠一些内置策略防止未处理的数据永久消失: - **消息持久化设置**:每条进入系统的记录都可以标记为“持久”,这意味着它们会被存储于硬盘而非仅仅驻留在内存里直到被消费为止[^3]。 - **镜像队列(Mirrored Queues)**:对于高可用需求场景下推荐使用这种技术,在多个节点间同步复制整个队列的内容从而提升容灾性能[^5]。 #### 消费端的消息安全接收 最后一步就是保证客户端能稳定获取所需资料而不会因为异常中断造成遗漏或者重复读取等问题出现: - **手动应答(Manual Acknowledgements)** :只有当应用程序显式告知 broker 它已完成某项任务之后才会删除对应项目副本。 - **限流控制(QoS Tuning)** : 调整预取计数(pre-fetch count),限制每次分发给单个工作进程的任务数量以减少压力并提高稳定性. ```python def callback(ch, method, properties, body): process_message(body) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=10) # 设置 QoS 参数 channel.basic_consume(queue='task_queue', on_message_callback=callback) print(' [*] Waiting for messages.') channel.start_consuming() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值