【mq读书笔记】mq读写分离机制
mq根据brokerName查找Broker地址的过程
mq根据MessageQueue查找Broker地址的唯一依据是brokerName,同一组Broker(M-S)他们的bokerName相同但brokerId不同,主服务器的brokerId为0,从服务器的brokerId大于0,rokckertMq提供mQClientFactory.findBrokerAddressInSubscribe来实现根据brokerName,brokerId查找Broker地址
org.apache.rocketmq.client.impl.consumer.PullAPIWrapper#pullKernelImpl:
public PullResult pullKernelImpl(
final MessageQueue mq,
final String subExpression,
final String expressionType,
final long subVersion,
final long offset,
final int maxNums,
final int sysFlag,
final long commitOffset,
final long brokerSuspendMaxTimeMillis,
final long timeoutMillis,
final CommunicationMode communicationMode,
final PullCallback pullCallback
) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
FindBrokerResult findBrokerResult =
this.mQClientFactory.findBrokerAddressInSubscribe(mq.getBrokerName(),
this.recalculatePullFromWhichNode(mq), false);
FindBrokerResult:
public class FindBrokerResult {
private final String brokerAddr;
private final boolean slave;
private final int brokerVersion;
org.apache.rocketmq.client.impl.factory.MQClientInstance#findBrokerAddressInSubscribe:
public FindBrokerResult findBrokerAddressInSubscribe(
final String brokerName,
final long brokerId,
final boolean onlyThisBroker
) {
String brokerAddr = null;
boolean slave = false;
boolean found = false;
//获取brokerName下的所有broker
HashMap<Long/* brokerId */, String/* address */> map = this.brokerAddrTable.get(brokerName);
if (map != null && !map.isEmpty()) {
//根据brokerId获取broker地址
brokerAddr = map.get(brokerId);
slave = brokerId != MixAll.MASTER_ID;
found = brokerAddr != null; if (!found && !onlyThisBroker) {
Entry<Long, String> entry = map.entrySet().iterator().next();
brokerAddr = entry.getValue();
slave = entry.getKey() != MixAll.MASTER_ID;
found = true;
}
} if (found) {
return new FindBrokerResult(brokerAddr, slave, findBrokerVersion(brokerName, brokerAddr));
} return null;
}
从ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> brokerAddrTable地址缓存表中根据brokerName获取所有的Broker信息。
根据brokerId从Broker主从缓存表中获取指定Broker名称,日过根据brokerId未找到相关条目,此时onlyThisBroker未false,则随机返回Broker中任意一个Broker,否则返回null。
根据消息消费队列获取brokerId的实现:
public long recalculatePullFromWhichNode(final MessageQueue mq) {
if (this.isConnectBrokerByUser()) {
return this.defaultBrokerId;
}
//pullFromWhichNodeTable是在哪初始化的?
AtomicLong suggest = this.pullFromWhichNodeTable.get(mq);
if (suggest != null) {
return suggest.get();
}
return MixAll.MASTER_ID;
}
从ConcurrentMap<MessageQueue, AtomicLong/* brokerId */> pullFromWhichNodeTable缓存表中获取该消息消费队列的brokerId,如果找到则返回,否则返回brokerName的主节点。
消息消费拉取线程PullMessageService根据PullRequest请求从主服务器拉取消息后会返回下一次建议拉取的brokerId,消息消费者线程在收到消息后,会根据主服务器的建议拉取brokerId来更新
pullFromWhichNodeTable。


org.apache.rocketmq.client.impl.consumer.PullAPIWrapper#updatePullFromWhichNode:
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);
}
}
消息服务端是根据何种规则来建议哪个消息消费队列该从哪台Broker服务器上拉取消息呢?
org.apache.rocketmq.store.DefaultMessageStore#getMessage:
long diff = maxOffsetPy - maxPhyOffsetPulling;
long memory = (long) (StoreUtil.TOTAL_PHYSICAL_MEMORY_SIZE
* (this.messageStoreConfig.getAccessMessageInMemoryMaxRatio() / 100.0));
getResult.setSuggestPullingFromSlave(diff > memory);
maxoffsetPy:主服务器消息存储文件最大偏移量
maxPhyPffsetPulling:此次拉取消息最大偏移量
diff:对于PullMessageService线程来说,当前未被拉取到消息消费端的消息长度。
TOTAL_PHYSICAL_MEMORY_SIZE:
mq所在服务器总内存大小。accessMessageInMemoryMaxRatio表示RocketMQ所能使用的最大内存比例,超过该内存,消息江北置换出内存;
memory表示RocketMQ消息常驻内存的大小,超过该大小,rocketMq将会将旧的消息置换回磁盘。
如果diff大于memory,表示当前需要拉去的消息已经超出了常驻内存的大小,表示主服务器繁忙,此时才建议从从服务器拉取。
org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest(Channel, org.apache.rocketmq.remoting.protocol.RemotingCommand, boolean):
if (getMessageResult != null) {
response.setRemark(getMessageResult.getStatus().name());
responseHeader.setNextBeginOffset(getMessageResult.getNextBeginOffset());
responseHeader.setMinOffset(getMessageResult.getMinOffset());
responseHeader.setMaxOffset(getMessageResult.getMaxOffset());
if (getMessageResult.isSuggestPullingFromSlave()) {
responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getWhichBrokerWhenConsumeSlowly());
} else {
responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
}
如果一个Master拥有多台Slave服务器,参与消息卡去负载的从服务器只会是其中一个。
【mq读书笔记】mq读写分离机制的更多相关文章
- 【mq读书笔记】消息过滤机制
mq支持表达式过滤和类过滤两种模式,其中表达式又分为TAG和SQL92.类过滤模式允许提交一个过滤类到FilterServer,消息消费者从FilterServer拉取消息,消息经过FilterSer ...
- 基于Keepalived高可用集群的MariaDB读写分离机制实现
一 MariaDB读写分离机制 在实现读写分离机制之前先理解一下三种主从复制方式:1.异步复制:MariaDB默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库 ...
- 【mq读书笔记】消息队列负载与重新分配(分配 新队列pullRequest入队)
回顾PullMessageService#run: 如果队列总没有PullRequest对象,线程将阻塞. 围绕PullRequest有2个问题: 1.PullRequest对象在什么时候创建并加入p ...
- 使用Amoeba实现mysql读写分离机制
Amoeba的实用指南 http://docs.hexnova.com/amoeba/ 如何实现mysql读写分离 : 通常来说有两种方式: 1,应用程序层实现 2,中间件层实现 应用层实现 应用层实 ...
- 【mq读书笔记】消息拉取长轮训机制(Broker端)
RocketMQ并没有真正实现推模式,而是消费者主动想消息服务器拉取消息,推模式是循环向消息服务端发送消息拉取请求. 如果消息消费者向RocketMQ发送消息拉取时,消息未到达消费队列: 如果不启用长 ...
- 【mq读书笔记】消息确认(失败消息,定时队列重新消费)
接上文的集群模式,监听器返回RECONSUME_LATER,需要将将这些消息发送给Broker延迟消息.如果发送ack消息失败,将延迟5s后提交线程池进行消费. 入口:ConsumeMessageCo ...
- 【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)
在https://www.cnblogs.com/lccsblog/p/12249265.html中,PullMessageService负责对消息队列进行消息拉取,从远端服务器拉取消息后将消息存入P ...
- 【mq读书笔记】消息拉取
疑问:PullRequest何时添加? PullMessageService提供延迟添加与立即添加2种方式 疑问:PullRequest是在什么时候创建的呢? 1.上上图中 PullRequest p ...
- 【mq读书笔记】mq消息消费
消息消费以组的的模式开展: 一个消费组内可以包含多个消费者,每一个消费组可订阅多个主题: 消费组之间有集群模式与广播模式两种消费模式:集群模式-主题下的同一条消息只允许被其中一个消费者消费.广播模式- ...
随机推荐
- python构造函数和析构函数
构造函数和析构函数 关注公众号"轻松学编程"了解更多. 1.构造方法的使用 很多类都倾向于将对象创建为有初始化状态.因此类可以定义一个名为__init__()的特殊方法(构造方 ...
- eyoucms破解授权/去版权插件
插件描述:eyoucms内容管理系统的授权破解,可以去版权的插件,需要请自行关注. https://hbh.cool/find/136.html
- Json Master masters JSON!
对于一个软件开发人员, JSON 是最熟悉的东西之一了, 每一个开发人员基本上每一天都会跟 JSON 打交道. 作为一个大前端开发人员, 当看到从服务器返回的 JSON 数据时, 尤其是大数据量或者复 ...
- zookeeper单机/集群安装和使用
简书原文地址:https://www.jianshu.com/p/88194fde9a07 或者关注我的公众号"进阶者euj" 前提是本机有jdk 一.单机安装 1.去官网下载zo ...
- 剑指offer之打印超过数组一半的数字
问题描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...
- leetcode133:3sum-closest
题目描述 给出含有n个整数的数组s,找出s中和加起来的和最接近给定的目标值的三个整数.返回这三个整数的和.你可以假设每个输入都只有唯一解. 例如,给定的整数 S = {-1 2 1 -4}, 目标值 ...
- LeetCode 热题 HOT 100(05,正则表达式匹配)
LeetCode 热题 HOT 100(05,正则表达式匹配) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力 ...
- Pytest学习(六) - conftest.py结合接口自动化的举例使用
一.conftest.py作用 可以理解成存放fixture的配置文件 二.conftest.py配置fixture注意事项 pytest会默认读取conftest.py里面的所有fixture co ...
- layui form表单提交
layui.use(['form'], function () { var form = layui.form; //监听提交 form.on('submit(formDemo)', function ...
- 内网渗透 day11-免杀框架
免杀框架 目录 1. venom框架 2. shelltel框架 3. backdoor factory(BDP) 1. venom框架 cd venom进入venom文件夹中./venom.sh进入 ...