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