Producer
端,每个实例在发消息的时候,默认会轮询所有的message queue
发送,以达到让消息平均落在不同的queue
上。而由于queue
可以散落在不同的broker
,所以消息就发送到不同的broker
下,如下图:
图中箭头线条上的标号代表顺序,发布方会把第一条消息发送至 Queue 0
,然后第二条消息发送至 Queue 1
,以此类推。
在集群消费模式下,每条消息只需要投递到订阅这个topic
的Consumer Group
下的一个实例即可。RocketMQ
采用主动拉取的方式拉取并消费消息,在拉取的时候需要明确指定拉取哪一条message queue
。
而每当实例的数量有变更,都会触发一次所有实例的负载均衡,这时候会按照queue
的数量和实例的数量平均分配queue
给每个实例。
默认的分配算法是AllocateMessageQueueAveragely
,如下图:
还有另外一种平均的算法是AllocateMessageQueueAveragelyByCircle
,也是平均分摊每一条queue
,只是以环状轮流分queue
的形式,如下图:
需要注意的是,集群模式下,queue
都是只允许分配只一个实例,这是由于如果多个实例同时消费一个queue
的消息,由于拉取哪些消息是consumer
主动控制的,那样会导致同一个消息在不同的实例下被消费多次,所以算法上都是一个queue
只分给一个consumer
实例,一个consumer
实例可以允许同时分到不同的queue
。
通过增加consumer
实例去分摊queue
的消费,可以起到水平扩展的消费能力的作用。而有实例下线的时候,会重新触发负载均衡,这时候原来分配到的queue
将分配到其他实例上继续消费。
但是如果consumer
实例的数量比message queue
的总数量还多的话,多出来的consumer
实例将无法分到queue
,也就无法消费到消息,也就无法起到分摊负载的作用了。所以需要控制让queue
的总数量大于等于consumer
的数量。
由于广播模式下要求一条消息需要投递到一个消费组下面所有的消费者实例,所以也就没有消息被分摊消费的说法。
在实现上,其中一个不同就是在consumer
分配queue
的时候,所有consumer
都分到所有的queue
。