面试题答案
一键面试消息发送负载均衡策略
- 轮询策略:
- 源码实现:在
DefaultMQProducerImpl
类的sendKernelImpl
方法中,selectOneMessageQueue
方法默认采用轮询方式选择MessageQueue
。例如:
public MessageQueue selectOneMessageQueue(final TopicPublishInfo publishInfo, final String lastBrokerName) { if (lastBrokerName == null) { return publishInfo.selectOneMessageQueue(); } else { return publishInfo.selectOneMessageQueue(lastBrokerName); } }
TopicPublishInfo
类中的selectOneMessageQueue
方法实现了轮询逻辑,每次调用会从messageQueueList
中选择下一个MessageQueue
。- 逻辑:依次从可用的
MessageQueue
列表中选择,保证每个MessageQueue
都有机会被选中,实现简单的负载均衡。
- 源码实现:在
- 随机策略:通过
Random
类在MessageQueue
列表中随机选择一个MessageQueue
。在自定义负载均衡策略时可以使用这种方式,例如在DefaultMQProducer
构造函数中,可以传入自定义的MessageQueueSelector
实现随机选择。 - 根据消息哈希值选择:
- 源码实现:在
DefaultMQProducer
中,如果使用MessageQueueSelector
的select
方法传入MessageQueueSelectorByHash
,会根据消息的某个属性(如消息体中的某个字段)计算哈希值,然后根据哈希值在MessageQueue
列表中选择。例如:
public class MessageQueueSelectorByHash implements MessageQueueSelector { @Override public MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg) { int value = arg.hashCode(); if (value < 0) { value = Math.abs(value); } return mqs.get(value % mqs.size()); } }
- 逻辑:根据消息相关的哈希值均匀分布到不同的
MessageQueue
,适合需要将相关消息发送到同一MessageQueue
的场景,如同一订单相关消息。
- 源码实现:在
消息消费负载均衡策略
- 集群消费模式下的负载均衡:
- 源码实现:
RebalanceImpl
类负责消费端的负载均衡。以AllocateMessageQueueAveragely
策略为例,allocate
方法实现如下:
public class AllocateMessageQueueAveragely implements AllocateMessageQueueStrategy { @Override public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll, List<String> cidAll) { // 省略部分代码 int averageSize = mqAll.size() <= cidAll.size()? 1 : mqAll.size() / cidAll.size(); int averageMod = mqAll.size() % cidAll.size(); int index = cidAll.indexOf(currentCID); List<MessageQueue> result = new ArrayList<>(); for (int i = 0; i < averageSize; i++) { result.add(mqAll.get((index * averageSize + i))); } if (averageMod > 0 && index < averageMod) { result.add(mqAll.get(cidAll.size() * averageSize + index)); } return result; } }
- 逻辑:将
MessageQueue
平均分配给各个消费者实例。先计算平均每个消费者应分配的MessageQueue
数量,再根据消费者实例在消费者列表中的索引,按顺序分配MessageQueue
,余数部分再依次分配给前几个消费者。
- 源码实现:
- 广播消费模式:每个消费者实例消费所有的
MessageQueue
中的消息,不需要负载均衡算法,因为每个消费者都要处理所有消息。
不同场景下优化负载均衡策略提高消息处理效率
- 高并发写场景:
- 优化策略:可以根据业务特点选择合适的消息发送负载均衡策略。如果业务数据没有明显的关联关系,随机策略可能更适合,因为可以充分利用多个
MessageQueue
的写入能力。如果数据有一定的分组关联性,如按用户ID分组,使用消息哈希值选择策略能保证同一用户的消息发送到同一MessageQueue
,减少消息处理时的跨队列协调。同时,可以增加MessageQueue
数量,提高写入并行度。
- 优化策略:可以根据业务特点选择合适的消息发送负载均衡策略。如果业务数据没有明显的关联关系,随机策略可能更适合,因为可以充分利用多个
- 高并发读场景:
- 优化策略:在集群消费模式下,选择合适的消费端负载均衡策略。如果消费者处理能力差异较大,可以采用
AllocateMessageQueueAveragelyByOrder
策略,它会根据消费者名称的字典序来分配MessageQueue
,尽量使处理能力强的消费者分配到更多MessageQueue
。另外,增加消费者实例数量,以提高消息处理并行度。还可以优化消费者内部的处理逻辑,如采用多线程处理消息,减少单个消费者处理消息的时间。
- 优化策略:在集群消费模式下,选择合适的消费端负载均衡策略。如果消费者处理能力差异较大,可以采用