最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于ZooKeeper的會話機制Session解讀

 更新時間:2023年02月15日 09:13:55   作者:FollowYourHeart2015  
這篇文章主要介紹了關(guān)于ZooKeeper的會話機制Session解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

一、為什么會有會話機制Session

ZooKeeper的架構(gòu)圖

首先我們看下ZooKeeper的架構(gòu)圖,client跟ZooKeeper集群中的某一臺server保持連接,發(fā)送讀/寫請求,讀請求直接由當前連接的server處理,寫請求由于是事務請求,由當前server轉(zhuǎn)發(fā)給leader進行處理。同時,client還能接收來自server端的watcher通知。

而所有的這些交互,都是基于client和ZooKeeper的server之間的TCP長連接,也稱之為Session會話

ZooKeeper對外的服務端口默認是2181,客戶端啟動時,首先會與服務器建立一個TCP連接,從第一次連接建立開始,客戶端會話的生命周期也開始了,通過這個連接,客戶端能夠通過心跳檢測和服務器保持有效的會話,也能夠向ZooKeeper服務器發(fā)送請求并接受響應,同時還能通過該連接接收來自服務器的Watch事件通知。

Session的SessionTimeout值用來設置一個客戶端會話的超時時間。當由于服務器壓力太大、網(wǎng)絡故障或是客戶端主動斷開連接等各種原因?qū)е驴蛻舳诉B接斷開時,只要在SessionTimeout規(guī)定的時間內(nèi)能夠重新連接上集群中任意一臺服務器,那么之前創(chuàng)建的會話仍然有效。

說點題外話,長連接、短連接、數(shù)據(jù)庫連接池:

短連接 :連接->傳輸數(shù)據(jù)->關(guān)閉連接

也可以這樣說:短連接是指SOCKET連接后發(fā)送后接收完數(shù)據(jù)后馬上斷開連接。

長連接:連接->傳輸數(shù)據(jù)->保持連接 -> 傳輸數(shù)據(jù)-> 。。。 ->關(guān)閉連接。

長連接指建立SOCKET連接后不管是否使用都保持連接,但安全性較差。

網(wǎng)絡中不同節(jié)點使用TCP協(xié)議通過SOCKET進行通信,首先需要3次握手建立連接,數(shù)據(jù)傳輸,4次握手斷開連接,因此如果頻繁的創(chuàng)建、關(guān)閉,是很耗費系統(tǒng)資源的,就像短連接那樣;使用長連接貌似彌補了短連接的缺點,但是,如果并發(fā)量過大,會有大量的長連接,同樣會耗費大量系統(tǒng)資源,因此具體選用長連接還是短連接,是要根據(jù)具體的場景來選擇。

ZooKeeper中一個client只會跟一個server進行交互(除非與當前server連接失敗,會切換到下個server),不管這種交互有多頻繁,只需要一個TCP長連接就足以應對,因選擇一個TCP長連接,不失為一種最好的方案。

數(shù)據(jù)庫連接池:我們在使用JDBC進行數(shù)據(jù)庫連接的時候,其實是建立了一個數(shù)據(jù)庫連接池,它本身是一種短連接+長連接的方案,我們通過JDBC的3個關(guān)鍵配置來說明下:

參數(shù)名稱參數(shù)說明默認值備注
minPoolSize連接池中保留的最小連接數(shù)5長連接
maxPoolSize連接池中保留的最大連接數(shù)15短連接
maxIdleTime最大空閑時間,如果超出空閑時間未使用,連接被收回

超過最小連接數(shù)后創(chuàng)建的連接,在最大空閑時間后如果未使用,是會被回收的,因此可以被理解為短連接。但是保留的最小連接數(shù),即使未被使用也會一直存在,等待被使用,因此可以理解為長連接。

好了,扯了這么遠,我們還是回到ZooKeeper是如何通過TCP長連接來管理它的Session會話的吧。

二、會話(Session)如何管理

2.1)SessionID的初始化

首先了解3個基本概念:

  • sessionID:會話ID,用來唯一標識一個會話,每次客戶端創(chuàng)建會話的時候,ZooKeeper都會為其分配一個全局唯一的sessionID
  • TimeOut:會話超時時間,如果客戶端與服務器之間因為網(wǎng)絡閃斷導致斷開連接,并在TimeOut時間內(nèi)未連上其他server,則此次會話失效,此次會話創(chuàng)建的臨時節(jié)點將被清理
  • ExpirationTime:下次會話超時時間點。ZooKeeper會為每個會話標記一個下次會話超時時間點,便于對會話進行“分桶管理”,同時也是為了搞笑低耗的實現(xiàn)會話的超時檢查與清理。其值接近于當前時間+TimeOut,但不完全相等,稍后會介紹。

在每次client向server發(fā)起“會話創(chuàng)建”請求時,服務端都會為其分配一個sessionID,現(xiàn)在看下sessionID是如何生成的。

在SessionTrackerImpl初始化的時候,會調(diào)用initializeNextSession來生成一個初始化的sessionID,之后在該sessionID的基礎上為每個會話進行分配,其初始化算法如下:

//是ZooKeeper服務器的會話管理器,負責會話的創(chuàng)建、管理和清理等工作
public class SessionTrackerImpl extends Thread implements SessionTracker {
   
    {...}

	//參數(shù)id為當前服務器的myid
    public static long initializeNextSession(long id) {
        long nextSid = 0;
        //此處采用無符號右移,是為了防止出現(xiàn)負數(shù)的情況
        nextSid = (System.currentTimeMillis() << 24) >>> 8;
        nextSid =  nextSid | (id <<56);
        return nextSid;
    }
    
	{...}
}

該邏輯計算后得到的sessionID的前8位確定了所在的機器,后56位使用當前時間的毫秒表示進行隨機。

2.2)分桶策略

SessionTrackerImpl通過**“分桶策略”來進行會話的管理,分桶的原則是將每個會話的“下次超時時間點”(ExpirationTime)**相同的會話放在同一區(qū)塊中進行管理,以便于ZooKeeper對會話進行不同區(qū)塊的隔離處理,以及同一區(qū)塊的統(tǒng)一處理,如下圖,橫坐標是一個個的超時時間點ExpirationTime:

分桶管理

每個會話創(chuàng)建完畢后,ZooKeeper就會為其計算ExpirationTime,計算方式大體如下:

ExpirationTime = CurrentTime(當前時間) + SessionTimeOut(會話超時時間)

但圖中標識的ExpirationTime并不是以上公式簡單的算出來的時間。因為在ZooKeeper的實際實現(xiàn)中,還做了一個處理。

ZooKeeper的Leader服務器在運行期間會定時的進行會話超時檢查,其時間間隔為ExpirationInterval(默認值2000毫秒),每隔2000毫秒進行一次會話超時檢查。

為了方便同時對多個會話進行超時檢查,完整的ExpirationTime計算方式如下:

ExpirationTime_ = CurrentTime + SessionTimeOut
ExpirationTime = ( ExpirationTime_/ExpirationInterval + 1 ) * ExpirationInterval

注意不要使用小學的乘法分配律把小括號給消化掉,它存在的目的就是為了保證ExpirationTime是ExpirationInterval的整數(shù)倍,那為什么要這樣做???

提高會話檢查的效率。讓創(chuàng)建時間臨近的會話,分配在一個桶中,實際生產(chǎn)環(huán)境中一個服務端會有很多客戶端會話,逐個檢查過期時間會非常耗時,把它們放在一個桶中批量處理,可以大大提高效率。

比如CurrentTime為1547046000、1547046001這樣的會話就會被分配在一個桶中。

其次,Leader每隔ExpirationInterval 毫秒進行會話的清理,而剛好 ExpirationTime 這個時間點是會話的失效時間點,如果發(fā)現(xiàn)失效,直接清理掉就OK,避免了檢查時未失效,但沒過幾毫秒又失效了這種情況。

比如,ExpirationTime 是1547046000,如果在1547045998的時刻檢查,發(fā)現(xiàn)還有效,但過了2ms之后就無效了。而如果會話超時檢查和會話超時時間在同一個時間節(jié)點的話,就會避免這種情況。

2.3)會話激活

為了保持client會話的有效性,在ZooKeeper運行過程中,client會在會話超時時間過期范圍內(nèi)向server發(fā)送PING請求來保持會話的有效性,俗稱“心跳檢測”。

同時server重新激活client對應的會話,這段邏輯是在SessionTrackerImpltouchSession中實現(xiàn)的。

先看下流程,再看源碼:

會話激活

再看下源碼實現(xiàn):

//sessionId為發(fā)起會話激活的client的sessionId,timeout為會話超時時間
synchronized public boolean touchSession(long sessionId, int timeout) {
        /*
         * sessionsById的結(jié)構(gòu)為 HashMap<Long, SessionImpl>(),每個sessionid都有一個對應的session實現(xiàn)
         * 這里取出對應的session實現(xiàn)
         */
        SessionImpl s = sessionsById.get(sessionId);
        // Return false, if the session doesn't exists or marked as closing
        if (s == null || s.isClosing()) {
            return false;
        }
        //計算當前會話的下一個失效時間,可以理解為ExpirationTime_New
        long expireTime = roundToInterval(System.currentTimeMillis() + timeout);
        //tickTime是上一次計算的超時時間,可以理解為ExpirationTime_Old
        if (s.tickTime >= expireTime) {
            // Nothing needs to be done
            return true;
        }
        //將ExpirationTime_Old對應的桶中的會話取出,SessionSet 是SessionImpl的集合
        SessionSet set = sessionSets.get(s.tickTime);
        if (set != null) {
        	//將舊桶中的會話移除
            set.sessions.remove(s);
        }
        //更新當前會話的下一次超時時間
        s.tickTime = expireTime;
        //從新桶中取出該會話,無則創(chuàng)建,有則更新
        set = sessionSets.get(s.tickTime);
        if (set == null) {
            set = new SessionSet();
            sessionSets.put(expireTime, set);
        }
        set.sessions.add(s);
        return true;
    }

好了,我們了解了是會話是如何激活的,那在什么時候會發(fā)起激活呢,也就是touchSession這個方法什么時候被觸發(fā)呢?

分以下兩種情況:

  • 只要client向server發(fā)送請求,包括讀或?qū)懻埱?,就會觸發(fā)一次激活;
  • 如果client發(fā)現(xiàn)在sessionTimeOut / 3 時間內(nèi)未尚和server進行任何通信,就會主動發(fā)起一次PING請求,進而觸發(fā)激活;

關(guān)于會話激活,可以舉個非常腦洞的例子:就像你跟房東租房,進行續(xù)簽一樣。合同是一年一年的續(xù)簽,這是理論情況下,但是中間免不了要跟房東打交道,比如洗衣機壞了,問問房東如何處理,這一問,糟了,從問的這一天開始,重新簽一年的合同吧(當然是把之前的租金結(jié)算一下);另外一種就是 租期一年 / 3 = 每個季度,主動的跟房東續(xù)簽下合同(當然也是把之前的租金結(jié)算一下)……

租房傷不起啊,個稅申報抵消房租,房東還不愿意[此處一個欲哭無淚的表情]

三、過期會話(Session)如何清理

一言蔽之吧,會話過期后,集群中所有server都刪除由該會話創(chuàng)建的臨時節(jié)點(EPHEMERAL)信息

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring boot+redis 監(jiān)聽過期Key的操作方法

    spring boot+redis 監(jiān)聽過期Key的操作方法

    這篇文章主要介紹了spring boot+redis 監(jiān)聽過期Key,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • 利用java制作一個小的目錄查詢器的方法

    利用java制作一個小的目錄查詢器的方法

    下面小編就為大家?guī)硪黄胘ava制作一個小的目錄查詢器的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Spring注解驅(qū)動開發(fā)實現(xiàn)屬性賦值

    Spring注解驅(qū)動開發(fā)實現(xiàn)屬性賦值

    這篇文章主要介紹了Spring注解驅(qū)動開發(fā)實現(xiàn)屬性賦值,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • 基于eclipse.ini內(nèi)存設置的問題詳解

    基于eclipse.ini內(nèi)存設置的問題詳解

    本篇文章是對eclipse.ini內(nèi)存設置的問題進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • Java--裝箱和拆箱詳解

    Java--裝箱和拆箱詳解

    本篇文章主要介紹了詳解Java 自動裝箱與拆箱的實現(xiàn)原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-07-07
  • SpringBoot框架搭建教程分享

    SpringBoot框架搭建教程分享

    這篇文章主要為大家詳細介紹了SpringBoot框架搭建教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java原生服務器接收上傳文件 不使用MultipartFile類

    Java原生服務器接收上傳文件 不使用MultipartFile類

    這篇文章主要為大家詳細介紹了Java原生服務器接收上傳文件,不使用MultipartFile類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Spring Boot分段處理List集合多線程批量插入數(shù)據(jù)的解決方案

    Spring Boot分段處理List集合多線程批量插入數(shù)據(jù)的解決方案

    大數(shù)據(jù)量的List集合,需要把List集合中的數(shù)據(jù)批量插入數(shù)據(jù)庫中,本文給大家介紹Spring Boot分段處理List集合多線程批量插入數(shù)據(jù)的解決方案,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Java代碼編譯和反編譯的那些事兒

    Java代碼編譯和反編譯的那些事兒

    這篇文章主要給大家介紹了關(guān)于Java代碼編譯和反編譯的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-05-05
  • Kafka消費客戶端協(xié)調(diào)器GroupCoordinator詳解

    Kafka消費客戶端協(xié)調(diào)器GroupCoordinator詳解

    這篇文章主要為大家介紹了Kafka消費客戶端協(xié)調(diào)器GroupCoordinator使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10

最新評論

托克托县| 鄂温| 昌吉市| 湾仔区| 涪陵区| 天峻县| 昌乐县| 米易县| 五华县| 岳普湖县| 漠河县| 米林县| 旬阳县| 柳州市| 江都市| 石河子市| 安岳县| 永川市| 阜平县| 哈尔滨市| 都昌县| 富源县| 鱼台县| 措勤县| 绥化市| 峡江县| 宁蒗| 瑞安市| 广宁县| 湟源县| 汾西县| 如东县| 大英县| 宜黄县| 夏河县| 永吉县| 尉氏县| 比如县| 沙洋县| 哈巴河县| 屯门区|