Apache ZooKeeper - 集群中 Leader 的作用_事务的请求处理与调度分析
文章目錄
- 事務性請求處理
- Leader 事務處理分析
- 預處理階段
- 事務處理階段
- 事務執行階段
- 響應階段
- 源碼分析
- 小結
Leader 服務器在 ZooKeeper 中的作主要是處理事務性的會話請求以及管理 ZooKeeper 集群中的其他角色服務器
那么 在接收到來自客戶端的事務性會話請求后,ZooKeeper 集群內部又是如何判斷會話的請求類型,以及轉發處理事務性請求的呢?
事務性請求處理
在 ZooKeeper 集群接收到來自客戶端的會話請求操作后,首先會判斷該條請求是否是事務性的會話請求。
對于事務性的會話請求,ZooKeeper 集群服務端會將該請求統一轉發給 Leader 服務器進行操作。Leader 服務器內部執行該條事務性的會話請求后,再將數據同步給其他角色服務器,從而保證事務性會話請求的執行順序,進而保證整個 ZooKeeper 集群的數據一致性。
在 ZooKeeper 集群的內部實現中,是通過什么方法保證所有 ZooKeeper 集群接收到的事務性會話請求都能交給 Leader 服務器進行處理的呢?
在 ZooKeeper 集群內部,集群中除 Leader 服務器外的其他角色服務器接收到來自客戶端的事務性會話請求后,必須將該條會話請求轉發給 Leader 服務器進行處理。 ZooKeeper 集群中的 Follow 和 Observer 服務器,都會檢查當前接收到的會話請求是否是事務性的請求,如果是事務性的請求,那么就將該請求以 REQUEST 消息類型轉發給 Leader 服務器。
在 ZooKeeper集群中的服務器接收到該條消息后,會對該條消息進行解析。分析出該條消息所包含的原始客戶端會話請求。之后將該條消息提交到自己的 Leader 服務器請求處理鏈中,開始進行事務性的會話請求操作。如果不是事務性請求,ZooKeeper 集群則交由 Follow 和 Observer 角色服務器處理該條會話請求,如查詢數據節點信息。
Leader 事務處理分析
以客戶端發起的創建節點請求 setData 為例,具體看看 ZooKeeper 集群的底層處理過程。
在 ZooKeeper 集群接收到來自客戶端的一個 setData 會話請求后,其內部的處理邏輯基本可以分成四個部分 ,分別是預處理階段、事務處理階段、事務執行階段、響應客戶端。
預處理階段
在預處理階段,主要工作是通過網絡 I/O 接收來自客戶端的會話請求。判斷該條會話請求的類型是否是事務性的會話請求,之后將該請求提交給PrepRequestProcessor 處理器進行處理。封裝請求事務頭并檢查會話是否過期,最后反序列化事務請求信息創建 setDataRequest 請求,在 setDataRequest 記錄中包含了要創建數據的節點的路徑、數據節點的內容信息以及數據節點的版本信息。最后將該請求存放在 outstandingChanges 隊列中等待之后的處理。
事務處理階段
在事務處理階段,ZooKeeper 集群內部會將該條會話請求提交ProposalRequestProcessor 處理器進行處理。
事務執行階段
在經過預處理階段和事務會話的投票發起等操作后,一個事務性的會話請求都已經準備好了,接下來就是在 ZooKeeper 的數據庫中執行該條會話的數據變更操作。
在處理數據變更的過程中,ZooKeeper 內部會將該請求會話的事務頭和事務體信息直接交給內存數據庫 ZKDatabase 進行事務性的持久化操作。之后返回 ProcessTxnResult 對象表明操作結果是否成功。
響應階段
在 ZooKeeper 集群處理完客戶端 setData 方法發送的數據節點創建請求后,會將處理結果發送給客戶端。
在響應客戶端的過程中,ZooKeeper 內部首先會創建一個 setDataResponse 響應體類型,該對象主要包括當前會話請求所創建的數據節點,以及其最新狀態字段信息 stat。
之后創建請求響應頭信息,響應頭作為客戶端請求響應的重要信息,客戶端在接收到 ZooKeeper 集群的響應后,通過解析響應頭信息中的事務 ZXID 和請求結果標識符 err 來判斷該條會話請求是否成功執行。
源碼分析
首先,ZooKeeper 集群在收到客戶端發送的事務性會話請求后,會對該請求進行預處理。在代碼層面,ZooKeeper 通過調用 PrepRequestProcessor 類來實現預處理階段的全部邏輯。
可以這樣理解:在處理客戶端會話請求的時候,首先調用的就是 PrepRequestProcessor 類。而在 PrepRequestProcessor 內部,是通過 pRequest 方法判斷客戶端發送的會話請求類型。如果是諸如 setData 數據節點創建等事務性的會話請求,就調用 pRequest2Txn 方法進一步處理。
protected void pRequest(Request request){...switch (request.type) {case OpCode.setData:SetDataRequest setDataRequest = new SetDataRequest(); pRequest2Txn(request.type, zks.getNextZxid(), request, setDataRequest, true);break;}}而在 pRequest2Txn 方法的內部,就實現了預處理階段的主要邏輯。如下面的代碼所示,首先通過 checkSession 方法檢查該條會話請求是否有效(比如會話是否過期等),之后調用 checkACL 檢查發起會話操作的客戶端在 ZooKeeper 服務端是否具有相關操作的權限。最后將該條會話創建的相關信息,諸如 path 節點路徑、data 節點數據信息、version 節點版本信息等字段封裝成setDataRequest 類型并傳入到 setTxn 方法中,最后加入處理鏈中進行處理。
case OpCode.setData:zks.sessionTracker.checkSession(request.sessionId, request.getOwner());SetDataRequest setDataRequest = (SetDataRequest)record;if(deserialize)ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);path = setDataRequest.getPath();validatePath(path, request.sessionId);nodeRecord = getRecordForPath(path);checkACL(zks, request.cnxn, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo, path, null);int newVersion = checkAndIncVersion(nodeRecord.stat.getVersion(), setDataRequest.getVersion(), path);request.setTxn(new SetDataTxn(path, setDataRequest.getData(), newVersion));nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());nodeRecord.stat.setVersion(newVersion);addChangeRecord(nodeRecord);小結
主要梳理了 ZooKeeper 集群中 Leader 服務器是如何處理事務性的會話請求的,并且在處理完事務性的會話請求后,是如何通知其他角色服務器進行同步操作的。
可以說在 ZooKeeper 集群處理事務性的請過程中,Follow 和 Observer 服務器主要負責接收客戶端的會話請求,并轉發給 Leader 服務器。而真正處理該條會話請求的是 Leader 服務器。
這就會引發一個問題:當一個業務場景在查詢操作多而創建刪除等事務性操作少的情況下,ZooKeeper 集群的性能表現的就會很好。
而如果是在極端情況下,ZooKeeper 集群只有事務性的會話請求而沒有查詢操作,那么 Follow 和 Observer 服務器就只能充當一個請求轉發服務器的角色, 所有的會話的處理壓力都在 Leader 服務器。
在處理性能上整個集群服務器的瓶頸取決于 Leader 服務器的性能。ZooKeeper 集群的作用只能保證在 Leader 節點崩潰的時候,重新選舉出 Leader 服務器保證系統的穩定性。這也是 ZooKeeper 設計的一個缺點。
總結
以上是生活随笔為你收集整理的Apache ZooKeeper - 集群中 Leader 的作用_事务的请求处理与调度分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache ZooKeeper - L
- 下一篇: Apache ZooKeeper - 集