文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
官网:https://rocketmq.apache.org/
中文社区:https://rocketmq-learning.com/
中文文档:https://github.com/apache/rocketmq/tree/master/docs/cn
最佳实践:https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md
设计文档:https://github.com/apache/rocketmq/blob/master/docs/cn/design.md
基本概念
Topic:
一类消息的集合,消息发送者将一类消息发送到一个主题中,例如订单模块将订单发送到
order_topic
中,而用户登录时,将登录事件发送到user_login_topic
中。
标签(Tag):
消息设置的标志,用于同一Topic下区分不同类型的消息,可以根据Topic+Tag实现消息的精细化生产和消费。
ConsumeGroup:
消息消费组,一个消费组拥有多个消费者,消费组首先在启动时需要订阅需要消费的Topic。
- 一个Topic可以被多个消费组订阅,同样一个消费组也可以订阅多个主题。
队列(Queue):
一个Topic可以有很多队列,消息都存在Queue上,默认是一个Topic在同一个Broker组中是4个。
- 如果一个Topic现在在2个Broker组中,那么就有可能有8个队列。
由于一个Topic可能会有很多的队列,消息发送到哪个队列上?
RocketMQ提供了两种消息队列的选择算法:
- 轮询算法。
- 最小投递延迟算法。
轮询算法:
- 一个队列一个队列发送消息,这些就能保证消息能够均匀分布在不同的队列下,默认的队列选择算法。
最小投递延迟算法:
- 每次消息投递的时候会统计投递的时间延迟,在选择队列的时候会优先选择投递延迟时间小的队列。
- 这种算法可能会导致消息分布不均匀的问题。
消费模式
集群模式:
同一Topic下的一条消息只会被同一消费组中的一个消费者消费。
- 消息被负载均衡到了同一个消费组的多个消费者实例上。
广播消费:
每条消息推送给集群内所有的消费者,保证消息至少被每个消费者消费一次。
- 通常用于刷新内存缓存。
Confirm机制
消息生产者把消息发送给MQ,如果接收成功,MQ会返回一个ack消息给生产者。
如果消息接收不成功,MQ会返回一个nack消息给生产者。
重试机制
集群消费下,重试机制的本质是 RocketMQ 的延迟消息功能。
Broker 端会为每个 Topic 创建一个重试队列 ,队列名称是:
%RETRY% + 消费者组名
,达到重试时间后将消息投递到重试队列中进行消费重试(消费者组会自动订阅重试 Topic)。最多重试消费 16 次,重试的时间间隔逐渐变长,若达到最大重试次数后消息还没有成功被消费,则消息将被投递至死信队列。
死信队列
死信队列用于处理无法被正常消费的消息。
当一条消息初次消费失败,消息队列会自动进行消息重试。
达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确地消费该消息,此时,消息队列不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。
RocketMQ将这种正常情况下无法被消费的消息称为死信消息,将存储死信消息的特殊队列称为死信队列。
Queue分配算法
一个Topic中的Queue只能由Consumer Group中的一个Consumer进行消费,而一个Consumer可以同时消费多个Queue中的消息。
那么Queue与Consumer间的配对关系是如何确定的,即Queue要分配给哪个Consumer进行消费?
常见的有四种策略,分别是:
平均分配策略、环形平均策略、一致性hash策略、同机房策略。
这些策略是通过在创建Consumer时的构造器传进去的。
平均分配策略(默认):
该算法是根据:
avg = QueueCount / ConsumerCount
的计算结果进行分配的。如果能够整除,则按顺序将avg个Queue逐个分配,如果不能整除,则将多余出的Queue按照Consumer顺序逐个分配。
环形分配策略:
环形平均算法是指,根据消费者的顺序,依次由Queue队列组成的环形图逐个分配,该方法不需要提前计算。
一致性哈希分配策略:
该算法会将consumer的hash值作为Node节点存放到hash环上,然后将queue的hash值也放到hash环上。
通过顺时针方向,距离queue最近的那个consumer就是该queue要分配的consumer。
一致性哈希算法可以有效减少由于消费者组扩容或缩容所带来的大量的Rebalance,所以它适合用在Consumer数量变化较频繁的场景。
但是一致性哈希算法也存在不足,就是分配效率较低,容易导致分配不均的情况。
即每个消费者消费的队列数,有可能相差很大,这样就会造成个别消费者压力过大。
- 可以引入虚拟桶,让queue在hash环中尽可能分配均匀。
机房分配策略:
该算法会根据queue的部署机房位置和consumer的位置,过滤出当前consumer相同机房的queue。
然后按照平均分配策略或环形平均策略对同机房queue进行分配。
如果没有同机房queue,则按照平均配策略或环形平均策略对所有queue进行分配。
Rebalance机制
Rebalance即再均衡:
- 指的是将⼀个Topic下的多个Queue在同⼀个Consumer Group中的多个Consumer间进行重新分配的过程。
它能够提升消息的并行消费能力。
哪些场景会触发Rebalance?
消费者所订阅Topic的队列数量发生变化。
比如动态调整了Topic对应的队列数量,那么此时肯定是要重新分配一下,也就是触发Rebalance再均衡。
例如⼀个Topic下5个队列,有2个消费者的情况下,那么就可以给其中⼀个消费者分配2个队列,给另⼀个分配3个队列。
假设调整到Topic下有7个队列,还是2个消费者的情况下,那么就可以给其中⼀个消费者分配4个队列,给另⼀个分配3个队列。
从而提升消息的并行消费能力。
像Broker扩容或缩容、Broker与NameServer间发生网络异常、Queue扩容或缩容等场景都可能导致消费者所订阅Topic的队列数量发生变化。
消费者组中消费者的数量发生变化。
比如动态添加了Consumer进行消费,那么此时肯定是要重新分配一下,也就是触发Rebalance再均衡。
例如,⼀个Topic下5个队列,在只有1个消费者的情况下,这个消费者将负责消费这5个队列的消息。
- 如果此时增加⼀个消费者,那么就可以给其中⼀个消费者分配2个队列,给另⼀个分配3个队列,从而提升消息的并行消费能力。
像Consumer Group扩容或缩容、Consumer与NameServer间发生网络异常、Consumer发生宕机等都会导致消费者组中消费者的数量发生变化。
由于⼀个队列最多分配给⼀个消费者,因此当某个消费者组下的消费者实例数量大于队列的数量时,多余的消费者实例将分配不到任何队列,等于是多余的消费者什么都不做,白白浪费。
Rebalance的危害?
消费暂停:
- 在只有一个Consumer时,其负责消费所有队列。
- 在新增了一个Consumer后会触发 Rebalance的发生。
- 此时原Consumer就需要暂停部分队列的消费,等到这些队列分配给新的Consumer后,这些暂停消费的队列才能继续被消费。
消费重复:
- Consumer在消费新分配给自己的队列时,必须接着之前Consumer 提交的消费进度的offset 继续消费。
- 然而默认情况下,offset是异步提交的,这个异步性导致提交到Broker的offset与Consumer实际消费的消息并不一致。
- 这个不一致的差值就是可能会重复消费的消息。
消费突刺:
- 由于Rebalance可能导致重复消费,如果需要重复消费的消息过多,或者因为Rebalance暂停时间过长从而导致积压了部分消息。
- 那么有可能会导致在Rebalance结束之后瞬间需要消费很多消息。
消息过滤
RocketMQ的消费者可以根据Tag进行消息过滤,也支持自定义属性过滤。
消息过滤目前是在Broker端实现的:
优点是减少了对于Consumer无用消息的网络传输。
缺点是增加了Broker的负担、而且实现相对复杂。
RocketMQ支持两种方式的消息过滤:一种是Tag过滤,另外一种是SQL过滤。