ZooKeeper - O'Reilly Media ----Zookeeper Internals (3)

觀察者

我們已經關注了首領和跟隨者的很多內容,但是這裏還有第三種類型的服務器還沒被討論到:觀察者。觀察者和跟隨者在一些方面是一樣的。是他們都對首領的提議信息提交相應,但是和跟隨者不同的是,觀察者不會參與到我們之前討論的選舉進程中,它們只是簡單的學習通過INFORM信息提交的提議。跟隨者和觀察者都稱爲學習者,因爲首領都會告訴他們狀態的變化。

 

         INFORM信息的原理

因爲觀察者不會通過投票來接受一個提議,首領不會像觀察者發送提議,首觀察者的信息不包括提議本身,僅僅是zxid.因此只是發送相應信息到觀察者不是使得觀察者能夠應用這個提議。這也就是使用INFORM信息的原因,這個信息僅僅是一個包含被提交的提議的提交信息。

簡單的說,跟隨者會獲取到兩部分信息,而觀察者只有一個。跟隨者獲取到廣播的提議,然後是一個簡單的ZXID的提交信息。相反的觀察者只是獲得了一個INFORM信息,也就是被提交的提議的內容。

 

參與到決定那些提議會被提交的投票過程中的服務器成爲參與者(PARTICIPANT)。一個參與者可能是首領也可能是一個跟隨者。相反的,觀察服務器我們稱呼爲觀察者。

 

觀察者的一個主要原因是能夠領過的對讀請求進行擴展,通過增加更多的觀察者,我們能夠處理更多的讀事務,同時不會犧牲寫的吞吐量。注意到寫的吞吐量是有法定人數數量來決定的。如果我們增加了更多的能夠投票的服務器,會增大法定人數的數量,同時會減少寫的吞吐量。然而添加觀察者也不是完全沒有代價的,每一個新的觀察者包括增加每次提交操作的一條額外信息。這個代價比起增加可以進行投票的服務器來說小的很多。

 

觀察者的另一個原因是形成一種可以孵化出多個數據中心的部署方式,跨越的散步在多個數據中心的參與者可能明顯的降低系統的性能,這是由於不同數據中心連接的延遲。而使用觀察者,更新操作可以在高吞吐率和低延遲的一個數據中心內完成,而通過觀察者使得數據向其他數據中心傳播。這樣其他位置的客戶端也可以使用這些數據了。注意到觀察者並不消除數據中心之間的網絡信息傳輸,因爲觀察者必須向首領推送更新請求和處理INFORM信息。它只是使得狀態更新的提交可以在一個數據中心內完成,因爲所有的參與者都是在一個數據中心內執行的。

 

服務器的框架

首領,跟隨者和觀察者最終都是服務器。我們實現一個服務器主要抽象就是請求處理器。一個請求處理器就是一個處理管道中不同狀態的一個抽象,每一個服務器會實現細一些的請求處理器。我們可以認爲每一個處理器就是增加到請求處理過程中的一個元素。當給定的請求被服務器處理管道中的所有處理器都處理完成後就可以認爲該請求已經被處理完成了。

 

         請求處理器

ZooKeeper源碼有一個叫做RequestProcessor的接口,這個接口的主要方法就是processRequest,輸入一個Request參數。在一個請求處理器的管道中,請求處理的連續處理器通常使用對來來進行拆分,當一個處理器要向下一個處理器發送請求時,會將請求添加到隊列中,該請求會一直保存到先一個處理器可以進行處理時取走。

 

獨立模式的服務器

ZooKeeper中最簡單的管道是獨立模式的服務器(ZookeeperServer,不進行復制)。圖9-6顯示了該類型服務器的管道。該管道擁有三個請求處理器哦:PreRequestProcessor,SyncRequestProcessor和FinalRequestProcessor。

PreRequestProcessor接收一個客戶端請求並執行,產生一個事務作爲結果。重新會議一下,事務就是一個直接作用在ZooKeeper數據樹上的操作的結果。事務數據以一個頭和一個事務記錄的格式添加到Request對象。這裏要注意只有改變ZooKeeper狀態的操作纔會包含事務,都操作不會產生事務。對於讀操作來說,Request對象中事務的屬性爲空。

 

下一個處理器就是SynRequestProcessor。SynReqeustProcessor負責將事務固話到硬盤,它本子上就是將事務添加到一個事務日記中和定時的生成鏡像。我們下章在詳細的描述硬盤的狀態。

 

接下來也就是最後一個處理器是FinalRequestProcessor。當一個Request對象包含事務時,它會將這些改變應用到ZooKeeper數據樹上。否則這個處理器只是讀取數據樹返回給客戶端。

 

首領服務器

當我們切換到法定人數處理模式時,服務器的處理管道會有一定改變,我們先充首領服務器的處理管道入手,圖9-77解釋了首領服務器的處理管道

第一個處理器依然是PreRequestProcessor,但接下來的處理器變成了Proposal–RequestProcessor。這個處理器會產生提議併發送到跟隨者。ProposalRequestProcessor將所有的請求推送到CommitRequestProcessor,同時將寫操作推送到SyncRequestProcessor。

 

SynReqeustProcessor上獨立模式服務器中的工作一樣,將事務固話到硬盤中,然後會出發Ack-RequestProcessor,一個給生成承認並返回給自己的簡單處理器。就像我們之前提到的,首領會期待法定人數中的每一個服務器返回承認,也包括自己。AckReqeustProcessor就負責處理這件事情。

 

ProposalRequestProcessor之後的另一個處理器是CommitReqeustProcessor。CommitRequestRequestProcessor會在接收到足夠的承認後提交提議。承認實際上會在Leader類(Leader. ProcessAck()方法)中進行處理,會將要給提交的請求添加到CommitRequestProcessor的一個隊列中。請求處理器的線程會處理這個隊列。

 

接下來也就是最後一個處理器FinalRequestProcessor,該處理和單獨模式中的是一樣的。Final-RequestProcessor將更新請求應用到數據樹和處理讀請求。在FinalRequestProcessor之前,有一個簡單的處理器叫ToBeAppliedRequestProcessor,即將應用的請求列表包含已經被法定人數承認,等待應用的請求,首領使用這個列表來和跟隨者們進行同步,當處理承認時會將請求添加到這個列表中。ToBeAppliedRequestProcessor在FinalRequestProcessor處理完請求之後會將元素從這個列表中移除。

 

注意到只有更新請求會被增加到即將應用列表中來由ToBeAppliedRequestProcessor負責移除。ToBeAppliedRequestProcessor對於讀操作來說不會執行任何操作,只是會讓FinalRequest –Processor來進行處理。

 

跟隨者和觀察者服務器

我們接下來描述跟隨者(FollowerRequestProcessor類)。圖9-8顯示了一個跟隨者使用的請求處理器。注意到這裏不是一個處理器序列,輸入也有不同的格式:客戶端請求,提議和響應。我們使用建通來指定跟隨者採取的不同路徑。


首先從FollwerRequestProcessor開始,該處理器接收並處理客戶端請求。FollowerRequestProcessor將請求推送到CommitRequestProcessor,另外會將寫請求推送到首領。CommitRequestProcessor將讀請求直接提交到FinalRequestProcessor,而對於寫請求來說,CommitRequestProcessor必須等待一個提交然後推送到FinalRequestProcessor。

 

當首領接收到一個新的寫請求,直接收到或有一個學習者轉發,會生成一個提議並推送到所有的跟隨者。當接收到一個提議時,跟隨者會發送到SyncRequestProcessor. SyncReqeustProcessor處理請求,在硬盤中進行記錄然後推送到SendAckRequestProcessor。SendRequestProcesscor。SendAckReqeustProcessor承認首領的提議。當首領接收到足夠的承認後就提交一個提議,發送提交信息到所有的跟隨者(併發送INFORM信息到觀察者)。當接收到一個提交信息,跟隨者使用CommitReqeustProcessor進行處理。

 

爲了保證執行的順序會被保存下來,CommitRequestProcessor當處罰一個寫請求時會暫停其他的請求。這以爲着我們在其接收到一個寫請求之後發送的讀請求會被阻塞知道寫請求通過CommitRequestProcessor。通過等待就保證了請求是按照接收到的順序來執行的。

 

觀察者服務器(ObserverZooKeeperServer服務器類)的請求處理管道和跟隨者非常相像。但是由於觀察者不需要承認這個提議,它不需要向首領發送承認信息或則是將事務固話到硬盤中。讓觀察者將事務固話到硬盤中也在討論之中,因爲這樣會加快觀察者的恢復。因此,可能在將來的發佈版本中會有這個特性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章