ZooKeeper源碼解析(7)-請求處理(上)

在前面的文章中,我們分析了Cluster模式的啟動過程,以及Zab的實現(xiàn).

在這篇文章中,我們會詳細介紹,ZooKeeper是如何處理每個請求的.

過程

ZooKeeper源碼解析(3)-Cluster啟動過程解析這篇文章中,我們介紹了,Cluster模式在啟動時,會創(chuàng)建一個用戶創(chuàng)建ServerCnxnServerCnxnFactory.默認情況下是NIOServerCnxnFactory

這不,在這里,我們再一次用到了NIOServerCnxnFactory

NIOServerCnxnFactoryrun()方法中,

我們可以看到,NIOServerCnxnFactory會根據(jù)不同的事件來做不同的事:

  • 如果是SelectionKey.OP_ACCEPT事件,代表客戶端請求建立一個新的連接,那么就創(chuàng)建一個NIOServerCnxn并且將其注冊到Selector中
  • 如果是SelectionKey.OP_READ | SelectionKey.OP_WRITE事件,那么就找到對應的NIOServerCnxn并執(zhí)行其doIO()方法.

我們來具體看一下NIOServerCnxndoIO()方法的實現(xiàn).

在這個方法中,會判斷目前發(fā)生的到底是SelectionKey.OP_READ事件還是SelectionKey.OP_WRITE事件.

我們先看一下,當發(fā)生的是SelectionKey.OP_READ事件時,會如何處理.

其實這里還是蠻難理解的.特別是readLength()這個函數(shù).

其實這段代碼的功能,我在注釋里已經(jīng)寫的很清楚了.

這段代碼的功能,總的來說,就是:

  • 判斷客戶端執(zhí)行的是不是monitor command
  • 如果是monitor command,那么在readLength()函數(shù)中就進行處理
  • 如果是其他的命令,那么就處理用戶請求

這里,我們需要清楚什么是monitor command.

monitor command就是監(jiān)控命令,就是能夠查看Server此時狀態(tài)的一些命令.這些命令都是四個字符的.

ZooKeeper Administrator's Guide中,我們可以看到,有這么一些Monitor Command

全部的Monitor Command請參考這個列表.

我們可以看到,其中有兩個很重要的變量,一個是incomingBuffer,一個是lenBuffer

我們看一下其定義:

我們可以看到,它們開始都是一個capacity為4的ByteBuffer.

我們可以看到,當有讀事件時,先將數(shù)據(jù)的前四個字節(jié)讀入incomingBuffer

我們可以看到,下面有一個if block,判斷語句為是否incomingBuffer == lenBuffer,而從上面的定義中,我們看到,incomingBuffer就是== lenBuffer

其實這里的重點是readLength()方法.

readLength()方法中,我們可以看到,如果前面的條件都通過,那么最后會重新初始化incomingBuffer

其實這段代碼,只要記住我上面說的功能,就很容易理解了.

這里也吐槽一下,起的名字這么難理解,而且感覺簡單的事情讓它給搞復雜了.

如果是Monitor Command,那么在readLength()方法以及后續(xù)的方法中,就對它進行處理了.

而如果不是Monitor Command,就要進入到readPayload()方法中處理.

readPayload()方法的主體如下:

我們可以看到,進行如下處理:

  • 如果此時Server還未初始化完成,那么就調(diào)用readConnectRequest()方法對ConnectRequest進行處理,然后將initialized設置為true.當然,這些都是readConnectRequest()方法內(nèi)部做的事情.
  • 如果Server已經(jīng)初始化完成,那么就調(diào)用readRequest()方法進行處理

我們可以看到,在Server未初始化完成之前,還是可以處理ConnectRequest的.

這里我們不深入去看readConnectRequest()的源碼,請讀者自行查看源碼來理解.

我們重點關(guān)注readRequest()方法.

在這個方法內(nèi)部,會調(diào)用ZooKeeperServerprocessPacket()方法.

而在processPacket()方法內(nèi)部,會調(diào)用submitRequest()方法,讓ZooKeeperServer中的RequestProcessor對請求進行處理.

我們看一下ZooKeeperServersubmitRequest()方法的主體:

那么,RequestProcessor是什么時候被配置的呢?

它是在啟動ZooKeeperServer的時候,配置的.

我們看一下ZooKeeper默認配置的RequestProcessor都有哪些.

我們可以看到,其中并沒有用于進行Zab算法提議的RequestProcessor

還記得我們在ZooKeeper源碼解析(3)-Cluster啟動過程解析這篇文章中,提到的,Server在發(fā)現(xiàn)自己是Leader之后,會啟動一個LeaderZooKeeperServer嗎?

沒錯,就是這里.

我們看看,LeaderZooKeeperServer都設置了哪些RequestProcessor

我們可以看到,其中就有用于Zab算法的提議的RequestProcessor

關(guān)于不同的RequestProcessor的介紹,我們會在下一篇文章中介紹.

我們這里主要關(guān)注PreRequestProcessor

我們可以看到,它的processRequest()方法的實現(xiàn),特別簡單:

就是非常簡單的添加到submittedRequests這個集合中.

那么何時來處理呢?

其實PreRequestProcessor是一個線程,在它啟動后,它就會不斷從submittedRequest中讀取數(shù)據(jù),并處理:

主要的處理函數(shù)就是pRequest()方法,其實現(xiàn)如下:

上面我們主要介紹了讀事件的處理過程,那么寫事件呢?

過程也很簡單,就是添加一些監(jiān)控信息,然后將數(shù)據(jù)發(fā)送給客戶端就好了.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容