ROCKETMQ 主從切換機制
阿新 • • 發佈:2019-01-30
之前看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( finalString 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能讀。
未完待續~