RocketMQ NameServer && Broker
什麼是 NameServer
Name Server 是專為 RocketMQ 設計的輕量級名稱服務,具有簡單、可叢集橫向擴充、無狀态等特點。
- 每個broker(包括master和slave)啟動的時候會向namesrv注冊
- Producer發送消息的時候 根據topic到namesrv擷取路由到broker的資訊
- Consumer 根據topic到namesrv擷取路由到broker的資訊
這裡需要注意一點的事,MetaQ 1.x和MetaQ 2.x是依賴ZooKeeper的,但RocketMQ(即MetaQ 3.x)卻去掉了ZooKeeper依賴,轉而采用自己的NameServer。
ZooKeeper是著名的分布式協作架構,提供了Master選舉、分布式鎖、資料的釋出和訂閱等諸多功能,為什麼RocketMQ沒有選擇ZooKeeper,而是自己開發了NameServer,我們來具體看看NameServer在RocketMQ叢集中的作用就明了了。
RocketMQ的Broker有三種叢集部署方式:1.單台Master部署;2.多台Master部署;3.多Master多Slave部署;采用第3種部署方式時,Master和Slave可以采用同步複制和異步複制兩種方式。下圖是第3種部署方式的簡單圖:

當采用多Master方式時,Master與Master之間是不需要知道彼此的,這樣的設計直接降低了Broker實作的複查性,你可以試想,如果Master與Master之間需要知道彼此的存在,這會需要在Master之中維護一個網絡的Master清單,而且必然設計到Master發現和活躍Master數量變更等諸多狀态更新問題,是以最簡單也最可靠的做法就是Master隻做好自己的事情(比如和Slave進行資料同步)即可,這樣,在分布式環境中,某台Master當機或上線,不會對其他Master造成任何影響。
那麼怎麼才能知道網絡中有多少台Master和Slave呢?你會很自然想到用ZooKeeper,每個活躍的Master或Slave都去約定的ZooKeeper節點下注冊一個狀态節點,但RocketMQ沒有使用ZooKeeper,是以這件事就交給了NameServer來做了(看上圖)。
結論一:NameServer用來儲存活躍的broker清單,包括Master和Slave。
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
每個屬性通過名字就能清楚的知道是什麼意思,之是以能用非線程安全的HashMap,是因為有讀寫鎖lock來對HashMap的修改做保護。我們注意到儲存broker的Map有兩個,即brokerAddrTable用來儲存所有的broker清單和brokerLiveTable用來儲存目前活躍的broker清單,而BrokerData用來儲存broker的主要資訊,而BrokerLiveInfo隻用來儲存上次更新(心跳)時間,我們可以直接看看RouteInfoManager中掃描非活躍broker的方法:
public void scanNotActiveBroker() {
Iterator<Entry<String, BrokerLiveInfo>> it = this.brokerLiveTable.entrySet().iterator();
while (it.hasNext()) {
Entry<String, BrokerLiveInfo> next = it.next();
long last = next.getValue().getLastUpdateTimestamp();
if ((last + BROKER_CHANNEL_EXPIRED_TIME) < System.currentTimeMillis()) {
RemotingUtil.closeChannel(next.getValue().getChannel());
it.remove();
log.warn("The broker channel expired, {} {}ms", next.getKey(), BROKER_CHANNEL_EXPIRED_TIME);
this.onChannelDestroy(next.getKey(), next.getValue().getChannel());
}
}
}
可以看出,如果兩分鐘内都沒收到一個broker的心跳資料,則直接将其從brokerLiveTable中移除,注意,這還會導緻該broker從brokerAddrTable被删除,當然,如果該broker是Master,則它的所有Slave的broker都将被删除。具體細節可以參看RouteInfoManager的onChannelDestroy方法。
結論二:NameServer用來儲存所有topic和該topic所有隊列的清單。
private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
我們注意到,topicQueueTable的value是QueueData的List,我們看看QueueData中的屬性:
public class QueueData implements Comparable<QueueData> {
private String brokerName;
private int readQueueNums;
private int writeQueueNums;
private int perm;
private int topicSynFlag;
}
是以,你幾乎可以在NameServer這裡知道topic相關的所有資訊,包括topic有哪些隊列,這些隊列在那些broker上等。
結論三:NameServer用來儲存所有broker的Filter清單。
關于這一點,讨論broker的時候再細說。
DefaultRequestProcessor是NameServer的預設請求處理器,他處理了定義在rocketmq-common子產品中RequestCode定義的部分請求,比如注冊broker、登出broker、擷取topic路由、删除topic、擷取broker的topic權限、擷取NameServer的所有topic等。
現在我們再回過頭來看看RocketMQ為什麼不使用ZooKeeper?ZooKeeper可以提供Master選舉功能,比如Kafka用來給每個分區選一個broker作為leader,但對于RocketMQ來說,topic的資料在每個Master上是對等的,沒有哪個Master上有topic上的全部資料,是以這裡選舉leader沒有意義;RocketMQ叢集中,需要有構件來處理一些通用資料,比如broker清單,broker重新整理時間,雖然ZooKeeper也能存放資料,并有一緻性保證,但處理資料之間的一些邏輯關系卻比較麻煩,而且資料的邏輯解析操作得交給ZooKeeper用戶端來做,如果有多種角色的用戶端存在,自己解析多級資料确實是個麻煩事情;既然RocketMQ叢集中沒有用到ZooKeeper的一些重量級的功能,隻是使用ZooKeeper的資料一緻性和釋出訂閱的話,與其依賴重量級的ZooKeeper,還不如寫個輕量級的NameServer,NameServer也可以叢集部署,NameServer與NameServer之間無任何資訊同步,隻有一千多行代碼的NameServer穩定性肯定高于ZooKeeper,占用的系統資源也可以忽略不計,何樂而不為?當然,這些隻是本人的一點了解,具體原因當然得RocketMQ設計和開發者來說。
來自:http://blog.csdn.net/manzhizhen/article/details/52606733
什麼是 Broker
與NameServer關系
連接配接:單個broker和所有nameserver保持長連接配接
心跳
心跳間隔:每隔30秒(此時間無法更改)向所有nameserver發送心跳,心跳包含了自身的topic配置資訊。
心跳逾時:nameserver每隔10秒鐘(此時間無法更改),掃描所有還存活的broker連接配接,若某個連接配接2分鐘内(目前時間與最後更新時間內插補點超過2分鐘,此時間無法更改)沒有發送心跳資料,則斷開連接配接。
斷開
時機:broker挂掉;心跳逾時導緻nameserver主動關閉連接配接
動作:一旦連接配接斷開,nameserver會立即感覺,更新topic與隊列的對應關系,但不會通知生産者和消費者
負載均衡
- 一個topic分布在多個broker上,一個broker可以配置多個topic,它們是多對多的關系。
- 如果某個topic消息量很大,應該給它多配置幾個隊列,并且盡量多分布在不同broker上,減輕某個broker的壓力。
- topic消息量都比較均勻的情況下,如果某個broker上的隊列越多,則該broker壓力越大。
可用性
由于消息分布在各個broker上,一旦某個broker當機,則該broker上的消息讀寫都會受到影響。是以rocketmq提供了master/slave的結構,salve定時從master同步資料,如果master當機,則slave提供消費服務,但是不能寫入消息,此過程對應用透明,由rocketmq内部解決。
可靠性
所有發往broker的消息,有同步刷盤和異步刷盤機制,總的來說,可靠性非常高。
同步刷盤時,消息寫入實體檔案才會傳回成功,是以非常可靠。
異步刷盤時,隻有機器當機,才會産生消息丢失,broker挂掉可能會發生,但是機器當機崩潰是很少發生的,除非突然斷電。
來自:http://blog.csdn.net/iie_libi/article/details/54236502
=============END=============
版權聲明:本文為CSDN部落客「weixin_34221036」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_34221036/article/details/92645099