主从读写分离机制:根据主服务器的消息堆积量来决定消费者是否向从服务器拉取消息消费
核心:
开关1:suggestPullingFromSlave:总开关,默认消费者不会消费从服务器。
开关2:suggestPullingFromSlave:未处理的消息总大小是否大于物理内存的40%
org.apache.rocketmq.store.GetMessageResult
// 总开关,默认消费者不会消费从服务器
private boolean suggestPullingFromSlave = false;
org.apache.rocketmq.store.DefaultMessageStore#getMessage()
// maxOffsetPy:当前最大物理偏移量
// maxPhyOffsetPulling:本次消息拉取最大物理偏移量
// diff:未处理的消息总大小,即消息堆积量
long diff = maxOffsetPy - maxPhyOffsetPulling;
// StoreUtil.TOTAL_PHYSICAL_MEMORY_SIZE:当前系统物理内存
long memory = (long) (StoreUtil.TOTAL_PHYSICAL_MEMORY_SIZE
* (this.messageStoreConfig.getAccessMessageInMemoryMaxRatio() / 100.0));
// 消息堆积量是否大于物理内存的40%,开关suggestPullingFromSlave设置true
getResult.setSuggestPullingFromSlave(diff > memory);
broker拉取消息读写分离处理:
org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest()
// 总开关slaveReadEnable是否等于true
if (this.brokerController.getBrokerConfig().isSlaveReadEnable()) {
// 消息堆积量是否等于大于物理内存的40%
// consume too slow ,redirect to another machine
if (getMessageResult.isSuggestPullingFromSlave()) {
// 设置从broker Id
responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getWhichBrokerWhenConsumeSlowly());
}
// consume ok
else {
responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getBrokerId());
}
} else { // 从主broker拉取消息
responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
}
consumer消费信息:
org.apache.rocketmq.client.impl.consumer.PullAPIWrapper#updatePullFromWhichNode()
/**
* 当消费者收到拉取响应回来的数据时,会将下次建议拉取的brokerId缓存起来,
* 下次拉取消息从pullFromWhichNodeTable中取出brokerId。
*/
public void updatePullFromWhichNode(final MessageQueue mq, final long brokerId) {
AtomicLong suggest = this.pullFromWhichNodeTable.get(mq);
if (null == suggest) {
this.pullFromWhichNodeTable.put(mq, new AtomicLong(brokerId));
} else {
suggest.set(brokerId);
}
}
参考:https://www.lmlphp.com/user/8368/article/item/378825/