Apache ZooKeeper - 集群中 Observer 的作用以及 与 Follow 的区别
文章目錄
- Pre
- Observer 介紹
- 源碼解析
- INFORM 消息
- Observer 處理鏈
- 小結(jié)
Pre
在 ZooKeeper 集群服務(wù)運行的過程中,Follow 服務(wù)器主要負責處理來自客戶端的非事務(wù)性請求,其中大部分是處理客戶端發(fā)起的查詢會話等請求。而在 ZooKeeper 集群中,Leader 服務(wù)器失效時,會在 Follow 集群服務(wù)器之間發(fā)起投票,最終選舉出一個 Follow 服務(wù)器作為新的 Leader 服務(wù)器。
除了 Leader 和 Follow 服務(wù)器,ZooKeeper 集群中還有一個 Observer 服務(wù)器。在 ZooKeeper 集群中,Observer 服務(wù)器對于提升整個 ZooKeeper 集群運行的性能具有至關(guān)重要的作用。
Observer 介紹
在 ZooKeeper 集群服務(wù)運行的過程中,Observer 服務(wù)器與 Follow 服務(wù)器具有一個相同的功能,那就是負責處理來自客戶端的諸如查詢數(shù)據(jù)節(jié)點等非事務(wù)性的會話請求操作。但與 Follow 服務(wù)器不同的是,Observer 不參與 Leader 服務(wù)器的選舉工作,也不會被選舉為 Leader 服務(wù)器。
我們把 Follow 服務(wù)器和 Observer 服務(wù)器統(tǒng)稱為 Learner 服務(wù)器。
Observer 服務(wù)器做的事情幾乎和 Follow 服務(wù)器一樣,那么為什么 ZooKeeper 還要創(chuàng)建一個 Observer 角色服務(wù)器呢?
想解釋這個問題,就要從 ZooKeeper 技術(shù)的發(fā)展過程說起,最早的 ZooKeeper 框架如下圖所示,可以看到,其中是不存在 Observer 服務(wù)器的。
在早期的 ZooKeeper 集群服務(wù)運行過程中,只有 Leader 服務(wù)器和 Follow 服務(wù)器。
不過隨著 ZooKeeper 在分布式環(huán)境下的廣泛應(yīng)用,早期模式的設(shè)計缺點也隨之產(chǎn)生,主要帶來的問題有如下幾點:
隨著集群規(guī)模的變大,集群處理寫入的性能反而下降。
ZooKeeper 集群無法做到跨域部署
其中最主要的問題在于,當 ZooKeeper 集群的規(guī)模變大,集群中 Follow 服務(wù)器數(shù)量逐漸增多的時候,ZooKeeper 處理創(chuàng)建數(shù)據(jù)節(jié)點等事務(wù)性請求操作的性能就會逐漸下降。這是因為 ZooKeeper 集群在處理事務(wù)性請求操作時,要在 ZooKeeper 集群中對該事務(wù)性的請求發(fā)起投票,只有超過半數(shù)的 Follow 服務(wù)器投票一致,才會執(zhí)行該條寫入操作。
正因如此,隨著集群中 Follow 服務(wù)器的數(shù)量越來越多,一次寫入等相關(guān)操作的投票也就變得越來越復(fù)雜,并且 Follow 服務(wù)器之間彼此的網(wǎng)絡(luò)通信也變得越來越耗時,導(dǎo)致隨著 Follow 服務(wù)器數(shù)量的逐步增加,事務(wù)性的處理性能反而變得越來越低。
為了解決這一問題, ZooKeeper 集群中創(chuàng)建了一種新的服務(wù)器角色,即 Observer——觀察者角色服務(wù)器。Observer 可以處理 ZooKeeper 集群中的非事務(wù)性請求,并且不參與 Leader 節(jié)點等投票相關(guān)的操作。這樣既保證了 ZooKeeper 集群性能的擴展性,又避免了因為過多的服務(wù)器參與投票相關(guān)的操作而影響 ZooKeeper 集群處理事務(wù)性會話請求的能力。
在引入 Observer 角色服務(wù)器后,一個 ZooKeeper 集群服務(wù)在部署的拓撲結(jié)構(gòu),如下圖所示:
在實際部署的時候,因為 Observer 不參與 Leader 節(jié)點等操作,并不會像 Follow 服務(wù)器那樣頻繁的與 Leader 服務(wù)器進行通信。因此,可以將 Observer 服務(wù)器部署在不同的網(wǎng)絡(luò)區(qū)間中,這樣也不會影響整個 ZooKeeper 集群的性能,也就是所謂的跨域部署。
源碼解析
首先,在我們平時開發(fā) ZooKeeper 服務(wù)的時候,如果想讓某個服務(wù)器以 Observer 角色運行,需要在該服務(wù)器的運行配置文件 zoo.cfg 文件中添加 peerType 屬性。如下所示,將該服務(wù)器的 peerType 屬性設(shè)置為 observer 。
peerType=observer而當 ZooKeeper 集群服務(wù)開始運行的時候,首先調(diào)用 ObserverZooKeeperServer 類,來實例化 ZooKeeper 集群中每個 Observer 服務(wù)器,并初始化調(diào)用鏈等相關(guān)操作。
ObserverZooKeeperServer(FileTxnSnapLog logFactory, QuorumPeer self, ZKDatabase zkDb) throws IOException {super(logFactory, self.tickTime, self.minSessionTimeout, self.maxSessionTimeout, zkDb, self);LOG.info("syncEnabled =" + syncRequestProcessorEnabled);在 ObserverZooKeeperServer 類的 commitRequest 函數(shù)中,就設(shè)置了與 Follow 角色不同的實現(xiàn)方式。如下面的代碼所示,Observer 不會接收網(wǎng)絡(luò)中的 Proposal 請求,不會像 Follow 一樣,在 Proposal 階段就獲得 Leader 服務(wù)器發(fā)送的變更數(shù)據(jù)。Observer 服務(wù)器是從 INFORM 數(shù)據(jù)包中獲得變更的數(shù)據(jù),在 commitRequest 函數(shù)的內(nèi)部實現(xiàn)中,提交執(zhí)行來自 INFORM 數(shù)據(jù)包中的事務(wù)操作。
public void commitRequest(Request request) { if (syncRequestProcessorEnabled) {// Write to txnlog and take periodic snapshotsyncProcessor.processRequest(request);}commitProcessor.commit(request);INFORM 消息
Observer 不會接收來自 Leader 服務(wù)器提交的投票請求,且不會接收網(wǎng)絡(luò)中的 Proposal 請求信息,只會從網(wǎng)絡(luò)中接收 INFORM 類型的信息包。
而 INFORM 信息的內(nèi)部只包含已經(jīng)被 Cmmit 操作過的投票信息,因為 Observer 服務(wù)器只接收已經(jīng)被提交處理的 Proposal 請求,不會接收未被提交的會話請求。這樣就隔離了 Observer 參與投票操作,進而使 Observer 只負責查詢等相關(guān)非事務(wù)性操作,保證擴展多個 Observer 服務(wù)器時不會對 ZooKeeper 集群寫入操作的性能產(chǎn)生影響。
Observer 處理鏈
接下來,我們再來看一下 Observer 服務(wù)器處理一次會話請求的底層實現(xiàn)過程。與 Leader 和 Follow 服務(wù)器一樣,在處理一條來自客戶單的會話請求時, Observer 同樣采用的是處理鏈的設(shè)計方式。在這個 Observer 處理鏈上,主要定義了三個處理器,處理器的執(zhí)行順序分別是 ObserverRequestProcessor 處理器、CommitProcessor 處理器以及 FinalRequestProcessor 處理器。
在 ObserverRequestProcessor 處理器中,首先判斷客戶端請求的會話類型,將所有事務(wù)性的會話請求交給 Leader 服務(wù)器處理,如下面的代碼所示。
public void run() {try {while (!finished) {Request request = queuedRequests.take();...switch (request.type) {case OpCode.sync:zks.pendingSyncs.add(request);zks.getObserver().request(request);break;case OpCode.create:case OpCode.create2:case OpCode.createTTL:case OpCode.createContainer:case OpCode.delete:case OpCode.deleteContainer:case OpCode.setData:case OpCode.reconfig:case OpCode.setACL:case OpCode.multi:case OpCode.check:zks.getObserver().request(request);break;...}} ...}}之后調(diào)用 CommitProcessor 處理器,將該條會話放入到 queuedRequests 請求等待隊列中。并喚醒相關(guān)線程進行會話處理。
queuedRequests 隊列實現(xiàn)了 BlockingQueue 阻塞隊列:當 queuedRequests 隊列容器已滿,生產(chǎn)者線程會被阻塞,直到隊列未滿;當隊列容器為空時,消費者線程會被阻塞,直至隊列非空時為止。 這就形成了一個消費者—生產(chǎn)者模式的處理方式。
public void processRequest(Request request) {if (stopped) {return;}if (LOG.isDebugEnabled()) {LOG.debug("Processing request:: " + request);}queuedRequests.add(request);wakeup();}在將會話請求放入到等待處理隊列后,CommitProcessor 處理器的 run 方法從該隊列中取出要處理的會話請求,然后解析會話請求中的請求服務(wù)器 zxid、請求事務(wù)信息 txn、請求頭信息 hdr 等,并封裝成 requeset 對象,然后傳遞給下一個處理器 FinalRequestProcessor。FinalRequestProcessor 處理器中會根據(jù)請求的類型,最終執(zhí)行相關(guān)的操作。
小結(jié)
與 Follow 服務(wù)器一樣,他們都可以處理 ZooKeeper 集群中的非事務(wù)性會話請求,不同之處在于,Observer 不參與 ZooKeeper 集群中 Leader 服務(wù)器的選舉以及事務(wù)性會話處理的投票工作。
利用 Observer 服務(wù)器的這一特性,在平時的生產(chǎn)環(huán)境中,可以采用什么樣的方式,來提高 ZooKeeper 集群服務(wù)的性能呢?
----所謂的跨域部署最常見的就是將 ZooKeeper 集群中的物理機器部署在不同的地域或機房中。
總結(jié)
以上是生活随笔為你收集整理的Apache ZooKeeper - 集群中 Observer 的作用以及 与 Follow 的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache ZooKeeper - 集
- 下一篇: Apache ZooKeeper - Z