簡單地說,ZooKeeper的連接與會(huì)話就是客戶端通過實(shí)例化ZooKeeper對象來實(shí)現(xiàn)客戶端與服務(wù)器創(chuàng)建并保持TCP連接的過程。本質(zhì)上,Session就是一個(gè)TCP 長連接。
(相關(guān)資料圖)
會(huì)話Session會(huì)話的作用:
ZK Server 執(zhí)行任何請求之前,都需要 Client 與 Server 先建立 Session;Client 提交給 Server 的任何請求,都必須關(guān)聯(lián)在 Session 上;Session 終止時(shí),關(guān)聯(lián)在 Session 上的臨時(shí)數(shù)據(jù)節(jié)點(diǎn)都會(huì)自動(dòng)消失;接受來自Server的Watcher事件通知;Session是ZooKeeper中的會(huì)話實(shí)體,代表了一個(gè)客戶端會(huì)話。其包含以下4個(gè)基本屬性。
sessionID:會(huì)話ID,用來唯一標(biāo)識(shí)一個(gè)會(huì)話,每次客戶端創(chuàng)建新會(huì)話的時(shí)候,ZooKeeper都會(huì)為其分配一個(gè)全局唯一的sessionID。TimeOut:會(huì)話超時(shí)時(shí)間。客戶端在構(gòu)造ZooKeeper實(shí)例的時(shí)候,會(huì)配置一個(gè)sessionTimeout參數(shù)用于指定會(huì)話的超時(shí)時(shí)間。ZooKeeper客戶端向服務(wù)器發(fā)送這個(gè)超時(shí)時(shí)間后,服務(wù)器會(huì)根據(jù)自己的超時(shí)時(shí)間限制最終確定會(huì)話的超時(shí)時(shí)間。TickTime:下次會(huì)話超時(shí)時(shí)間點(diǎn)。為了便于ZooKeeper對會(huì)話實(shí)行“分桶策略”管理,同時(shí)也是為了高效低耗地實(shí)現(xiàn)會(huì)話的超時(shí)檢查與清理,ZooKeeper會(huì)為每個(gè)會(huì)話標(biāo)記一個(gè)下次會(huì)話超時(shí)時(shí)間點(diǎn)。TickTime是一個(gè)13位的long型數(shù)據(jù),其值接近于當(dāng)前時(shí)間加上TimeOut,但不完全相等。isClosing:該屬性用于標(biāo)記一個(gè)會(huì)話是否已經(jīng)被關(guān)閉。通常當(dāng)服務(wù)端檢測到一個(gè)會(huì)話已經(jīng)超時(shí)失效的時(shí)候,會(huì)將該會(huì)話的isClosing屬性標(biāo)記為“已關(guān)閉”,這樣就能確保不再處理來自該會(huì)話的新請求了。會(huì)話重連當(dāng)客戶端和服務(wù)端之間的網(wǎng)絡(luò)連接斷開時(shí),ZooKeeper客戶端會(huì)自動(dòng)進(jìn)行反復(fù)的重連,直到最終成功連接上ZooKeeper集群中的一臺(tái)機(jī)器。在這種情況下,再次連接上服務(wù)端的客戶端有可能會(huì)處于以下兩種狀態(tài)之一。
CONNECTED:如果在會(huì)話超時(shí)時(shí)間內(nèi)重新連接上了ZooKeeper集群中任意一臺(tái)機(jī)器,那么被視為重連成功。EXPIRED:如果是在會(huì)話超時(shí)時(shí)間以外重新連接上,那么服務(wù)端其實(shí)已經(jīng)對該會(huì)話進(jìn)行了會(huì)話清理操作,因此再次連接上的會(huì)話將被視為非法會(huì)話。當(dāng)客戶端與服務(wù)端之間的連接斷開后,用戶在客戶端可能主要會(huì)看到兩類異常:CONNECTION_LOSS(連接斷開)和SESSION_EXPIRED(會(huì)話過期)。
連接斷開:CONNECTION_LOSS有時(shí)會(huì)因?yàn)榫W(wǎng)絡(luò)閃斷導(dǎo)致客戶端與服務(wù)器斷開連接,或是因?yàn)榭蛻舳水?dāng)前連接的服務(wù)器出現(xiàn)問題導(dǎo)致連接斷開,我們統(tǒng)稱這類問題為“客戶端與服務(wù)器連接斷開”現(xiàn)象,即CONNECTION_LOSS。在這種情況下,ZooKeeper客戶端會(huì)自動(dòng)從地址列表中重新逐個(gè)選取新的地址并嘗試進(jìn)行重新連接,直到最終成功連接上服務(wù)器。
會(huì)話失效:SESSION_EXPIRED
SESSION_EXPIRED是指會(huì)話過期,通常發(fā)生在CONNECTION_LOSS期間??蛻舳撕头?wù)器連接斷開之后,由于重連期間耗時(shí)過長,超過了會(huì)話超時(shí)時(shí)間(sessionTimeout)限制后還沒有成功連接上服務(wù)器,那么服務(wù)器認(rèn)為這個(gè)會(huì)話已經(jīng)結(jié)束了,就會(huì)開始進(jìn)行會(huì)話清理。但是另一方面,該客戶端本身不知道會(huì)話已經(jīng)失效,并且其客戶端狀態(tài)還是DISCONNECTED。之后,如果客戶端重新連接上了服務(wù)器,那么很不幸,服務(wù)器會(huì)告訴客戶端該會(huì)話已經(jīng)失效(SESSION_EXPIRED)。在這種情況下,用戶就需要重新實(shí)例化一個(gè)ZooKeeper對象,并且看應(yīng)用的復(fù)雜情況,重新恢復(fù)臨時(shí)數(shù)據(jù)。
會(huì)話失效的情況對于連接斷開的場景下,Zk客戶端會(huì)自動(dòng)嘗試重連其他節(jié)點(diǎn);但是會(huì)話失效的場景就需要考慮了,畢竟涉及到臨時(shí)節(jié)點(diǎn)和Watcher,那么影響就會(huì)很大的。比如注冊中心或是分布式鎖的應(yīng)用場景。
會(huì)話失效的情況一般有如下幾種情況:
網(wǎng)絡(luò)原因JVM內(nèi)存不足導(dǎo)致Full GC磁盤內(nèi)存不足程序bug為什么會(huì)說到JVM?其實(shí)這也是最容易忽略的問題,尤其是Java應(yīng)用的監(jiān)控沒有上的情況下。首先Zookeeper本身就是一個(gè)Java應(yīng)用,其內(nèi)存管理是受到了JVM的內(nèi)存設(shè)置限制的。因此,對于這一類托管在JVM上的應(yīng)用程序,必須考慮到JVM內(nèi)存設(shè)置的問題。
如何解決?
對于失效的場景,比較合適的就是增加了一個(gè)監(jiān)聽器;監(jiān)聽session expired事件,并且在事件發(fā)生的時(shí)候進(jìn)行處理。什么處理?自然是客戶端重新拉起zk連接會(huì)話。
package com.xiaoju.dqa.prometheus.client.zookeeper;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.state.ConnectionState;import org.apache.curator.framework.state.ConnectionStateListener;import org.apache.zookeeper.CreateMode;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class SessionConnectionListener implements ConnectionStateListener { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private String path; private String data; public SessionConnectionListener(String path, String data) { this.path = path; this.data = data; } @Override public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState){ if(connectionState == ConnectionState.LOST){ logger.error("[負(fù)載均衡失敗]zk session超時(shí)"); while(true){ try { if(curatorFramework.getZookeeperClient().blockUntilConnectedOrTimedOut()){ curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, data.getBytes("UTF-8")); logger.info("[負(fù)載均衡修復(fù)]重連zk成功"); break; } } catch (InterruptedException e) { break; } catch (Exception e){ } } } }}
參考
Zookeeper Curator 處理會(huì)話過期 Session Expired
優(yōu)化hbase JVM GC 參數(shù),避免由于JVM內(nèi)存回收引發(fā)的ZooKeeper會(huì)話超時(shí)進(jìn)程退出事件
zookeeper恢復(fù)了,線上微服務(wù)卻全部掉線了,怎么回事?
Copyright @ 2015-2022 華中晚報(bào)網(wǎng)版權(quán)所有 備案號: 京ICP備12018864號-26 聯(lián)系郵箱:2 913 236 @qq.com