ROCKETMQ 主从切换机制

来源:互联网 发布:金贵软件怎么样 编辑:程序博客网 时间:2024/06/05 13:12

       之前看rocketmq,然后在想一个问题,就是一主一从的集群结构中,如果master宕机了,consumer这边是怎么选择的,按照官方说明中,master挂了,但是slave中的消息仍然可以被consume消费到,然后master恢复后,master的消息又可以被消费到。

       那么问题来了,consumer是怎么从master上面切换到slave上继续消费消息呢?首先明确一点,master宕机,就意味着这个broker不再写入,但是因为slave还在,所以还可以继续读。所以我们看一下consumer是怎么选择的?其实还有个疑问,就是master宕机后,会体现到负载均衡服务的重新分配吗?

       先说第一个问题,跟代码进去:

       PullConsumer:


PullResult pullResult =                        consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
一路next 到  
pullAPIWrapper.pullKernelImpl
然后发现,消费者消费从哪个服务器上面拉信息是通过这样确定的:
public FindBrokerResult findBrokerAddressInSubscribe(    final String brokerName,    final long brokerId,    final boolean onlyThisBroker) {    String brokerAddr = null;    boolean slave = false;    boolean found = false;    HashMap<Long/* brokerId */, String/* address */> map = this.brokerAddrTable.get(brokerName);    if (map != null && !map.isEmpty()) {        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;}
这里稍微解释下rocketmq的broker机制 :
broker-a 
    master   ip1   0
    slave1   ip2   1
    slave2   ip3   2
一个broker—name 下面拥有若干个服务实例(一主二从),他们角色可能不同(master和slave),但是他们对于同一个brokername拥有唯一的id(0,1,2)。
所以我们上面想讲的是对于broker-a这个拓扑结构而言,如果从上面拉消息,会选哪个ip的服务器去真实拉取。
上面代码显示,选择的时候需要传入名字和id,这样其实已经在拓扑结构中唯一确定一台机器了。但是凡事有意外,比如,你选的这台机器刚好宕机了,怎么办?
宕机后,因为consumer是发心跳的,所以本地服务会清除掉原来机器的信息,于是找不到了。代码中的做法是,从剩下的选一个,考虑到map无序,所以当做随机好了。
这样子,只要这个拓扑结构还有一台存活,就一定能够返回一个ip地址供consumer连接。
所以这个传入的brokerid很重要,正常情况下应该都是0,即master。到从的时候应该都是大于0的值,这样就是slave了。
ok,我们看下这个传入的brokerid怎么确定的?
public long recalculatePullFromWhichNode(final MessageQueue mq) {    if (this.isConnectBrokerByUser()) {        return this.defaultBrokerId;    }    AtomicLong suggest = this.pullFromWhichNodeTable.get(mq);    if (suggest != null) {        return suggest.get();    }    return MixAll.MASTER_ID;}
1.是否设置ConnectBrokerByUser,默认是false,对应的defaultBrokerId是0,即master
2.本地缓存中是否存有suggest,有就直接返回
3.直接返回master,即0

演练一下:
consumer启动,发现没有设置,缓存也没有,于是返回master的brokerid,然后从地址缓存中找到了ip,顺利拉到了消息,再更新本地的suggest缓存。
然后下一次,再步骤2中返回上一次设置的suggest值作为brokerid,继续流程。
master开始宕机,然后consumer的地址缓存更新后,清除了master的地址信息。这时候触发了consumer从slave上面拉的效果,这就是消费从master切换到slave的过程。
那什么时候master恢复后,slave怎么切回去呢?
一开始我是有疑问的,因为我以为切到slave后,salve的brokerid会写入到suggest里面,然而并没有。
slave的borkerid写入到suggest缓存的话,即使master恢复后,因为slave并没有消失,所以不会触发重选过程,自然切不到master上面。
重点来了,这个suggest其实是broker端返回的。
什么意思呢?
我即使是从slave中拉取数据,但是slave 的broker端在返回值中携带了一个suggest的值,这个值是0.这就是说slave还是建议你下次拉去优先从master中拉取,
即使master已经宕机了,还是从优先选master,这个suggest是由服务器决定的,不是consumer客户端。
所以最后的问题是,broker代码逻辑中,什么时候返回0(master),什么时候返回非0(slave).
大部分时候,是返回0的,即master。
几个过程会返回非0 :
1.master消息堆积太严重,会返回一个预先设置好的slave brokerid,默认值是1,所以brokerid不要乱设置,容易出事。
2.
问题二:
master宕机会引发负载均衡服务的变化吗?
猜测:
首先生产者肯定是受影响的,因为不能写了。
消费者应该是不受影响的,因为slave能读。
未完待续~

        

       

原创粉丝点击