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,然后再慢慢进行处理。

 

RabbitMQ是一个开源的消息代理,它支持多种消息协议。RabbitMQ高可用性是指在RabbitMQ集群中,当某个节点出现故障时,其他节点可以接管它的工作,从而保证整个集群的可用性。以下是实现RabbitMQ高可用的步骤: 1. 安装RabbitMQ并启用日志插件 ```shell rabbitmq-plugins enable rabbitmq_tracing ``` 2. 配置RabbitMQ集群 在RabbitMQ集群中,每个节点都需要知道其他节点的存在。可以通过以下命令将节点加入到集群中: ```shell rabbitmqctl stop_app # 停止应用 rabbitmqctl reset # 重置节点 rabbitmqctl join_cluster rabbit1@ydt1 --ram # 将节点加入到集群中,--ram表示为内存节点,如果不加--ram表示为磁盘持久化节点 rabbitmqctl start_app # 启动应用 ``` 其中,rabbit1@ydt1是集群中的一个节点,可以根据实际情况进行修改。 3. 配置镜像队列 镜像队列是指将队列的消息在多个节点之间进行复制,从而保证在某个节点出现故障时,其他节点可以接管它的工作。可以通过以下命令创建镜像队列: ```shell rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' # 创建名为ha-all的策略,将所有队列设置为镜像队列 ``` 4. 配置负载均衡 在RabbitMQ集群中,可以通过负载均衡来均衡各个节点的负载,从而提高整个集群的性能。可以使用Nginx等负载均衡软件来实现。 --相关问题--: 1. RabbitMQ如何保证消息的可靠性? 2. RabbitMQ如何实现消息的延迟发送? 3.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值