RocketMQ高可用分析

1、集群
NameServer集群
为无状态集群

broker集群
1)多master模式
2)多master和多slave(异步)
3)多master和多slave(同步)

2、主从复制方式
1)、同步复制
消息从Master复制到Slave后才给客户端发送ACK,表示写成功

安全可靠,如果Master出故障,Slave有全部备份数据,容易恢复。但是会降低吞吐量。

2)、异步复制
消息只要在Master上写成功后就会给客户端发送ACK。
不可靠,会造成消息丢失,如果Master出故障,则会造成部分数据丢失。但是响应快,低延时,搞吞吐量

实际应用中药结合业务场景,合理组合刷盘方式和主从赋值方式。同步刷盘,由于会频繁触发磁盘写动作,会明显降低性能。通常情况下刷盘方式选择异步。然后主从赋值方式选择同步。即使有一台机器出故障,保证数据不丢失。

3、负载均衡
1)Producer负载均衡
Producer端,每个实例发送消息的时候,默认会轮询所有的Message queue发送,已达到让消息平均落到不同的queue上。而由于queue可以散落在不同的broker上,所有消息就发送到不同的broker上,从而达到负载均衡的效果

2)Consumer负载均衡

集群模式
在集群模式下,每个消息只需要投递到订阅这个topic的Consumer Group下的一个实例即可。MQ主动拉取并消费消息,在拉取的时候需要明确指定拉取哪一条Message queue。
而每当实例的数量发生变化,都会触发一次Rebalance,安照queue的数量和实例的数量平均分配queue给每个实例。

默认方式:AllocateMessageQueueAveragely

javaclient rocketmq高可用 rocketmq高可用原理_负载均衡


注意:

1、集群模式下,queue只允许分配给一个实例,如果允许多个实例同时消费同一个queue的消息,由于拉取哪些消息去消费是consumer主动控制的,就会导致同一个消息被不同的实例下消费多次。

2、如果consumer实例数量大于queue的数量,将会出现闲置实例。所以要控制实例的数量要小于等于queue的数量

3、启动多个消费者,就会负载消费消息,可以水平扩展,每次增加或者减少实例数量,都会触发负载均衡,原来被分配到的queue将会被分配到其他实例上继续消费广播模式

javaclient rocketmq高可用 rocketmq高可用原理_分布式_02


广播模式下要求一条消息需要投递到一个消费组下的所有消费者实例,所以没有消息被分摊的说法。在事实上,其中一个不同就在consumer分配queue的时候,所有的consumer都分配到所有的queue。

4、消息重试
顺序消息的重试
对于顺序消息,当消费者消费失败后,RocketMq会自动不断进行消息重试(每隔1秒)。这时如果不去处理消费失败的情况,将会造成消息消费被阻塞。因为消息是顺序的,后面的消费者都在等待前面的消费者成功消费消息。所以务必要及时监控并处理消费失败的情况。

无序消息的重试

对于无序消息(普通、定时、延迟、事务消息),当消费消息失败后。可以设置返回状态,达到重试的效果。无序消息的重试只针对集群消费方式。对于广播方式不提供重试特性,当消费失败后,也不进行重试,继续消费新的消息。

默认允许每条消息最多重试16次,具体时间间隔如下表

javaclient rocketmq高可用 rocketmq高可用原理_队列_03


配置方式

1)消息失败后,重试配置的方式

//1、方式一
return Action.RecomsumeLater;
//2、方式二
return null;
//3、方式三
throw new RuntimeException("Consumer Message Exception");

2)消费失败,不重试配置方式

return Action.CommitMessage;

允许对重试次数进行自定义,如设置次数超过16次,则每次重试间隔时间为2小时。

Properties properties = new Properties();
properties.put(PropertyKeyConst.MaxReconsumeTimes,"20");
Consumer consumer = ONSFactory.createConsumer(properties);

注意:
1、如自定义了重试次数,将会对相同Group下的所有consumer实例都生效。
2、如果相同Group下的Consumer都设置了重试次数,则以最后启动的Consumer实例为准,会覆盖之前实例的配置。

5、死信队列
如果一个消息被重试的次数超过了最大重试次数,最终会被放到死信队列
有效期与正常消息相同,都是3天。三天后会被自动删除。

死信队列有如下特征:
1、一个死信队列对应一个Group ID,而不是消费者实例。
2、如果Group ID 未产生死信消息,RocketMQ也不会创建死信队列。
3、一个死信队列包含了对应Group ID 产生的所有死信消息,不论该消息属于哪个Topic。

6、消息的幂等性
同一个消息不管消费了多少次,结果是一样

重复消息产生
1)发送时消息重复
生产者给MQ发送消息后,由于网络抖动,投递给MQ的消息后,MQ没有及时发ACK给生产者,导致超时,生产者再次发送消息
投递时消息重复
2)消费方处理了MQ的消息后,在发送ACK给MQ前,出现了网络闪断,MQ在网络恢复后再次尝试投递之前的消息。
3)负载均衡时消息重复
当某个broker宕机后重启、扩容或缩容时,会触发Rebalance,此时消费者可能收到重复的消息

处理消息重复消费
处理方式
不建议通过messageID进行幂等处理,因为messageID可能重复。所以真正安全的幂等处理,最好使用以业务唯一标识作为幂等处理的关键依据。而业务的唯一标识可以通过消息key进行设置。