RabbitMQ的高可用

1.Rabbit集群

采用集群模式保护消息的完整。

1.1普通集群

在普通集群模式下,各个节点之间有相同的元数据,即队列结构,而消息不会冗余(不同节点的消息不同)。

消费时,如果消费的不是存有数据的节点,RabbitMQ会临时在节点之间进行数据传输,将消息从存有数据的节点传输到消费的节点。(客户端拉取消息时临时同步

缺点:

1**.普通集群的可靠性低,如果有个节点服务宕机了,那这个节点上的数据就无法消费了,需要等到这个节点服务恢复后才能消费**。此时,消费者端已经消费过的消息就有可能给不了服务端正确应答,等服务重启后,可能会造成部分消息重复消费。另外,如果消息没有做持久化,重启服务消息就会丢失。

2.普通集群模式也不支持高可用,即当某一个节点服务挂了后,需要手动重启服务,才能保证这一部分消息能正常消费。

1.2镜像集群

这种模式是在普通集群模式基础上的一种增强方案,这也就是RabbitMQ的官方HA高可用方案。需要在搭建了普通集群之后再补充搭建。其本质区别在于,这种模式会在镜像节点中间主动进行消息同步,而不是在客户端拉取消息时临时同步。

集群内部有一个算法会选举产生master和slave,当一个master挂了后,也会自动选出一个来。从而给整个集群提供高可用能力。

这种模式的消息可靠性更高,因为每个节点上都存着全量的消息。而他的弊端也是明显的,集群内部的网络带宽会被这种同步通讯大量的消耗,进而降低整个集群的性能。这种模式下,队列数量最好不要过多。

2.RabbitMQ如何保证消息不丢失

2.1那些环节会有丢失消息的可能?

在上图中,1,2,4三个场景都是跨网络的,而跨网络就肯定会有丢消息的可能

然后关于3这个环节,通常MQ存盘时都会先写入操作系统的缓存page cache中,然后再由操作系统异步的将消息写入硬盘 。这个中间有个时间差 ,就可能会造成消息丢失。如果服务挂了,缓存中还没有来得及写入硬盘的消息就会丢失。这也是任何用户态的应用程序无法避免的。

2.2RabbitMQ消息零丢失方案

2.2.1生产者保证消息正确发送到RabbitMQ

对于单个消息,使用生产者确认机制

RabbitMQ的生产者确认机制分为同步确认和异步确认同步确认 主要是通过在生产者端指定一个等待确认的完成时间异步确认机制 则是通过在生产者端注入两个回调确认函数第一个函数是在生产者消息发送成功时调用,第二个函数则是生产者消息发送失败时调用。两个函数需要通过sequenceNumber自行完成消息的前后对应。sequenceNumber的生成方式需要通过channel的序列获取。int sequenceNumber = channel.getNextPublishSeqNo();

当前版本的RabbitMQ,可以在Producer中添加一个ReturnListener监听那些成功发到Exchange,但是却没有路由到Queue的消息

如果发送批量消息,在RabbitMQ中,另外还有一种手动事务的方式,可以保证消息正确发送。

2.2.2RabbitMQ存盘不丢消息

对于Classic经典队列,直接将队列声明成为持久化队列 即可。而新增的Quorum队列和Stream队列,都是明显的持久化队列,能更好的保证服务端消息不会丢失。(同步存盘和异步存盘)(避免不了OS刷盘时服务器宕掉丢数据)

2.2.3RabbitMQ主从消息同步不丢消息

首先他的普通集群模式,消息是分散存储的,不会主动进行消息同步了,是有可能丢失消息的。而镜像模式集群,数据会主动在集群各个节点当中同步,这时丢失消息的概率不会太大。

尽量使用镜像集群

2.2.4RabbitMQ消费者不丢消息

RabbitMQ在消费消息时可以指定是自动应答,还是手动应答 。如果是自动应答模式,消费者会在完成业务处理后自动进行应答,而如果消费者的业务逻辑抛出异常,RabbitMQ会将消息进行重试,这样是不会丢失消息的,但是有可能会造成消息一直重复消费。

而将RabbitMQ的应答模式设定为 手动应答****可以提高消息消费的可靠性。

3.如何保证消息幂等

产生原因:RabbitMQ的自动重试功能导致重复消费消息。默认情况下,RabbitMQ会无限次数的重复进行消息消费。

解决方案:

1)设定RabbitMQ的重试次数,不要让其进行无限次数的重试;

2)在业务上处理幂等问题 :处理幂等问题的关键是要给每个消息一个唯一的标识 。 在SpringBoot框架集成RabbitMQ后,可以给每个消息指定一个全局唯一的MessageID ,在消费者端针对MessageID做幂等性判断。在RabbitMQ中,消息的头部就是一个很好的携带数据的地方。

4.如何保证消息的顺序

在RabbitMQ当中,针对消息顺序的设计其实是比较弱的。唯一比较好的策略就是单队列+单消息推送。 即一组有序消息,只发到一个队列中,利用队列的FIFO特性保证消息在队列内顺序不会乱。

然后在消费者进行消费时,保证只有一个消费者 ,同时指定prefetch属性为1,即每次RabbitMQ都只往客户端推送一个消息

在多队列情况下,如何保证消息的顺序性,目前使用RabbitMQ的话,还没有比较好的解决方案。

5.关于RabbitMQ的数据堆积问题

如果出现了消息堆积比较严重的场景,就需要从数据流转的各个环节综合考虑

首先在消息生产者端 :对于生产者端,最明显的方式自然是降低消息生产的速度 。但是,生产者端产生消息的速度通常是跟业务息息相关的,一般情况下不太好直接优化。但是可以选择尽量多采用批量消息的方式,降低IO频率

然后在RabbitMQ服务端 : 从前面的分享中也能看出,RabbitMQ本身其实也在着力于提高服务端的消息堆积能力。对于消息堆积严重的队列,可以预先添加懒加载机制,或者创建Sharding分片队列,这些措施都有助于优化服务端的消息堆积能力 。另外,尝试使用Stream队列,也能很好的提高服务端的消息堆积能力

接下来在消息消费者端 :要提升消费速度最直接的方式,就是增加消费者数量了。尤其当消费端的服务出现问题,已经有大量消息堆积时。这时,可以尽量多的申请机器,部署消费端应用,争取在最短的时间内消费掉积压的消息。但是这种方式需要注意对其他组件的性能压力。

当确实遇到紧急状况,来不及调整消费者端时,可以 紧急上线一个消费者组 ,专门用来将消息快速转录。保存到数据库或者Redis,然后再慢慢进行处理。

相关推荐
茶杯梦轩1 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯3 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840823 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840825 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者6 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者8 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧9 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖9 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农9 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者9 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端