ZooKeeper集群中的跟隨者對客戶端請求的處理流程解讀(二)
前篇簡要回顧:在ZooKeeper集群選舉完成之后,各個集群節點各就各位,領導者開始領導、跟隨者開始跟隨,我們已經看到跟隨者建立和領導者的連接,并接受領導者的命令開始恢復,恢復完成之后領導者給了跟隨者一個UPTODATE命令,跟隨者開始進入接客狀態。。。
那么這里出現了兩條線,跟隨者一方面開始接客(接收并處理客戶端的讀寫請求,為ZK客戶端服務),另一方面跟隨者保持和領導者的密切連接,通過連接做一些事情,這個會在后面講到,我們先看看跟隨者是如何接客的,這也是和文章的標題相呼應。
跟隨者為客戶端服務的入口在這里我們通過NettyServerCnxnFactory這個類介紹,這個類是ZK通過Netty(NIO框架)來處理網絡層業務的實現,我的之前一篇文章(http://jvmplus.duapp.com /blog/view/B143299758)有介紹Netty在ZooKeeper中的應用,其中介紹了NettyServerCnxnFactory 是如何基于Netty建立網絡連接、獲取連接通道、接收和發送網絡數據的,關于這部分讀者可以直接簡要閱讀下那篇文章,這里我么你直接往下走,看ZK是如 何和客戶端進行互動的。
看下NettyServerCnxnFactory的 processMessage方法,這個方法主要是用來處理通道數據的,這里ZK對客戶端的連接通道主要消息類型有兩種,分別是 ResumeMessageEvent(回復通道事件)和Netty從通道拿到數據并封裝的原始類型,即非ResumeMessageEvent類型。 ResumeMessageEvent類型消息是ZK通過實現Netty的MessageEvent接口實現的一種消息事件類型,主要是用來區別是原始網 絡通道讀取的客戶端消息事件,還是ZK通過Netty的ChannelPipeline類的sendUpstream方法向通道上傳的消息事件類型數據, 后面processMessage方法會針對這兩種不同類型的消息事件類型做不同的事情。
當從通道中讀取ResumeMessageEvent類型的消息事件類型的時候,ZK做的事情主要是回復通道,將通道設置為可讀(OP_READ)模式。
這里主要是看下ZK對非 ResumeMessageEvent類型的消息事件類型的處理,ZK為了防止通道的數據量太大,發生擁堵現象,ZK給 NettyServerCnxn(代表ZK和客戶端連接的抽象)設置了一個字段throttled,它用來標識當前通道的數據是不是可以直接拿來處理,也 就是當處理的速度跟不上IO的速度額度時候,ZK會將throttled這個值設置為true,如果是throttled狀態,則ZK將讀取的消息放入內 存等待處理隊列里面;如果當前通道處于非throttled狀態,ZK首先看看等待隊列是不是有數據在等待,如果有,ZK將讀取的數據寫入等待隊列里面, 然后開始處理隊列數據。如果隊列為空,則ZK直接處理通道的數據,然后看看是否還有剩余,如果通道有剩余數據則將剩余數據寫入等待隊列。下面用圖簡單表示 一下ZK在這里對客戶端端口網絡消息的處理流程:
接 下來就是NettyServerCnxn的receiveMessage方法是如何對通道拿到的消息進行處理的,ZK這里會首先判斷是否有可讀消息,并且 再次判斷throttled的狀態,如果不滿足可讀的條件則關閉和客戶端的連接,通常正常狀態的ZK和客戶端的連接應該是長連接,這里為什么為斷開?這里 應該是發生了異常,也就是通道接收到了消息事件,但是又是不可讀,則ZK會關閉和客戶端的連接。
這 里ZK會判斷連接的狀態,如果是未初始化狀態則ZK會把這個請求是當做連接請求,否則會會交給processPacket來處理。 processPacket會首先解析客戶端請求包的類型,包括auth、sasl和普通類型三種,前兩種類型是認證和授權相關的,后面有機會再介紹,這 里主要介紹普通類型包的處理過程,于是到了ZooKeeperServer的submitRequest這個方法,總算快要開始ZK對客戶端請求處理流程 的核心部分了。
下篇文章進入ZooKeeper對客戶端請求處理流程的核心部分。