日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Tomcat集群应用同步 —— 源码分析

發(fā)布時(shí)間:2024/3/26 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tomcat集群应用同步 —— 源码分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 前言
  • 一、應(yīng)用同步的配置與實(shí)現(xiàn)原理
  • 二、應(yīng)用同步源碼分析
  • 三、如何獲取集群的節(jié)點(diǎn)列表
  • 四、通訊模塊Tribe
  • 五、集群的Session同步
  • 六、集群的Session共享
  • 總結(jié)


前言

相信大家對(duì)Tomcat的集群部署都不陌生,以往,我們手動(dòng)搭建一個(gè)Tomcat的集群環(huán)境,然后手動(dòng)部署每個(gè)Tomcat上面的應(yīng)用,保證他們都是相同的應(yīng)用程序包,以便負(fù)載均衡的時(shí)候不會(huì)出現(xiàn)問(wèn)題

但是問(wèn)題來(lái)了,如果我們項(xiàng)目源碼修改了,重新打包,這時(shí)候就要給每個(gè)Tomcat單獨(dú)替換里面的war包,相當(dāng)麻煩!

Tomcat給我們提供了一種十分簡(jiǎn)單的解決方案:

應(yīng)用同步


一、應(yīng)用同步的配置與實(shí)現(xiàn)原理

大家在修改Tomcat的server.xml配置文件的時(shí)候,應(yīng)該都注意到了他這一行注釋,
cluster這個(gè)單詞格外的引人矚目,沒(méi)錯(cuò)他就是Tomcat里面集群的配置類,他里面提供了我們想要的應(yīng)用同步的而功能!

前提,我們已經(jīng)配置了多個(gè)Tomcat的集群環(huán)境,可以用nginx或者Apache做負(fù)載均衡器。
然后我們只需在server.xml配置中的 標(biāo)簽里面添加下面紅色框里面的配置,就可以在集群環(huán)境,開(kāi)啟各個(gè)Tomcat之間的應(yīng)用自動(dòng)同步的功能。這里的配置是設(shè)置了 temp/ 目錄作為臨時(shí)保存同步war文件的目錄, webapps/目錄作為T(mén)omcat的部署目錄, watch/目錄是監(jiān)聽(tīng)目

Tomcat在啟動(dòng)的時(shí)候,會(huì)開(kāi)啟一個(gè)定時(shí)任務(wù),一直檢測(cè)監(jiān)聽(tīng)目錄文件改變,只要里面的文件保存時(shí)間改變了,就觸發(fā)一系列方法,更新(傳輸與接收)war包到集群中的其他節(jié)點(diǎn)。
集群環(huán)境的每個(gè)節(jié)點(diǎn)都實(shí)現(xiàn)了發(fā)送端、與接收端的任務(wù),每個(gè)節(jié)點(diǎn)他們是相等的關(guān)系,實(shí)際上嗎,沒(méi)有主從之分。

二、應(yīng)用同步源碼分析

監(jiān)聽(tīng)watch目錄是怎么監(jiān)聽(tīng)文件變化的,又是怎么處理相關(guān)邏輯的,下面我們根據(jù)源碼來(lái)了解!
我們先從集群節(jié)點(diǎn)中的,同步請(qǐng)求發(fā)送端開(kāi)始講起。

tomcat在啟動(dòng)時(shí),開(kāi)啟的定時(shí)任務(wù),會(huì)調(diào)用SimpleTcpCluster類的backgroundProcess(),里面通過(guò)clusterDeployer對(duì)象,調(diào)用其父類FarmWarDeployer的backgroundProcess()


在FarmWarDeployer的backgroundProcess方法中,調(diào)用了WarWatcher的check()方法,這個(gè)方法只要就是實(shí)現(xiàn)監(jiān)聽(tīng)文件,做文件的變更判斷

WarWatcher的check()方法中,有兩個(gè)核心的地方:

  • 獲取配置文件指定的監(jiān)聽(tīng)目錄下的文件列表
  • 遍歷文件獲取上次文件修改時(shí)間做對(duì)比,判斷到文件修改了,就執(zhí)行war包同步的邏輯

  • 上面走到的fileModified()方法,是FarmWarDeployer類下的一個(gè)方法,這個(gè)類主要是實(shí)現(xiàn)部署war包的。
    觸發(fā)了FarmWarDeployer的fileModified()方法后,調(diào)用里面的copy()復(fù)制war包到指定的部署目錄(實(shí)現(xiàn)這臺(tái)tomcat的部署)

    下面再調(diào)FarmWarDeployer的install()方法,獲取集群的節(jié)點(diǎn)列表


    再給集群節(jié)點(diǎn)發(fā)送同步的請(qǐng)求

    下面的源碼分析就到了集群同步接收端的節(jié)點(diǎn),如何實(shí)現(xiàn)獲取應(yīng)用并實(shí)現(xiàn)部署

    Tomcat在啟動(dòng)的時(shí)候,會(huì)開(kāi)啟一個(gè)定時(shí)任務(wù)NioReplicationTask,他會(huì)開(kāi)啟通道,定時(shí)接收同步請(qǐng)求

    在drainChannel()方法里面,源碼一層一層地點(diǎn)進(jìn)去后發(fā)現(xiàn),調(diào)用的是FarmWarDeployer的check()方法

    再通過(guò)反射調(diào)用HostConfig的check()方法

    然后通過(guò)deployApps()再調(diào)用deployWAR()方法,在這一行,將已經(jīng)封裝好的應(yīng)用數(shù)據(jù)添加到context,里面調(diào)用StandardHost的addChild

    將這個(gè)context(應(yīng)用)部署到host里面

    三、如何獲取集群的節(jié)點(diǎn)列表

  • 通過(guò)SimpleTcpCluster的registerMember(),用來(lái)注冊(cè)一個(gè)集群節(jié)點(diǎn)
  • SimpleTcpCluster的unregisterMember(),用來(lái)排除一個(gè)集群節(jié)點(diǎn)

  • tomcat啟動(dòng)的時(shí)候通過(guò)生命周期Lifecycle執(zhí)行SimpleTcpCluster的startInternal(),先注冊(cè)自己作為localMember

  • 啟動(dòng)一個(gè)線程(McastServiceImpl里面的線程類ReceiverThread),一直循環(huán)調(diào)用receive()一直通過(guò)socket不停地接收來(lái)自局域網(wǎng)等網(wǎng)段的信息(網(wǎng)絡(luò)中各個(gè)ip一直在相互ping)

    調(diào)用memberDataReceived(),將信息封裝成member(包含ip等信息)

    當(dāng)這次調(diào)用的member被判斷到是不在集群中,就調(diào)用里面的service.memberAdded()
    注意:這里雖然調(diào)用了memberAdded(),但是不一定會(huì)加入到當(dāng)前集群列表

  • 然后里面一層一層調(diào)用memberAdded()

    當(dāng)調(diào)用到TcpFailureDetector的memberAdded(),如果這里的notify是true,就代表當(dāng)前member跟localMember(這臺(tái)tomcat)是屬于同一集群的

    notify這個(gè)值,是通過(guò)Membership來(lái)實(shí)現(xiàn)多播心跳發(fā)送與接收,只要server.xml配置了SimpleTcpCluster,他就會(huì)啟用Membership來(lái)實(shí)現(xiàn)多播心跳檢測(cè)。

    同一集群的tomcat如果都配置了SimpleTcpCluster,也就能接收對(duì)方的心跳,就將這個(gè)notify設(shè)置為true,只有屬于同一集群的,才會(huì)調(diào)用到SimpleTcpCluster的memberAdded(),在這里判斷,如果該節(jié)點(diǎn)還沒(méi)注冊(cè),就調(diào)registerMember()注冊(cè)

    四、通訊模塊Tribe

    Apache Tribes是Tomcat的一個(gè)模塊,支持服務(wù)器集群中的組通信。

    Tribes是一個(gè)具有組通信能力的消息傳遞框架,這些是在Tomcat 5容器的集群/session復(fù)制代碼之外創(chuàng)建的。它是為T(mén)amcat集群實(shí) 現(xiàn)提供的通信框架。它的目的之一是簡(jiǎn)化分布式應(yīng)用點(diǎn)對(duì)點(diǎn)(peer-to-peer)及點(diǎn)對(duì)組(peer-to-group)通信。Tribes支持兩種 類型的消息傳遞:可用于兩個(gè)節(jié)點(diǎn)間事件的并發(fā)(concurrent)消息傳遞和可用于發(fā)送消息給多個(gè)節(jié)點(diǎn)的平行(parallel)消息傳遞

    整個(gè)Tribes的設(shè)計(jì)核心可以用下圖表示:

    Tribes的設(shè)計(jì)思路,主要是通過(guò)攔截器與監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)的,攔截器則是對(duì)底層數(shù)據(jù)的一種統(tǒng)一額外加工處理,監(jiān)聽(tīng)器則作為接口提供應(yīng)用層對(duì)數(shù)據(jù)做業(yè)務(wù)邏輯處理,組成了一個(gè)優(yōu)雅的設(shè)計(jì)方案

    • 應(yīng)用層:

    應(yīng)用層面主要就是一些監(jiān)聽(tīng)器,Tomcat內(nèi)置了一些類,實(shí)現(xiàn)了這些監(jiān)聽(tīng)器里面指定的方法,接受IO層傳輸過(guò)來(lái)的信息,并對(duì)其做響應(yīng)的邏輯處理。

    • 攔截器棧:

    攔截器棧提供了在消息傳送到應(yīng)用層之前對(duì)消息進(jìn)行一些額外的操作,例如對(duì)某些信息進(jìn)行過(guò)濾編碼等等操作。

    • 在IO層有三個(gè)重要的模塊:

    MembershipService 模塊主要負(fù)責(zé)組成員關(guān)系的維護(hù),包括維護(hù)現(xiàn)有成員及發(fā)現(xiàn)新成員。
    ChannelSender 模塊負(fù)責(zé)向組內(nèi)其他成員發(fā)送消息及其各種機(jī)制的詳細(xì)實(shí)現(xiàn)
    ChannelReceiver 模塊用于接收組內(nèi)其他成員發(fā)送過(guò)來(lái)的消息及其各種機(jī)制的詳細(xì)實(shí)現(xiàn)

    下面我會(huì)從底層往上,逐層通過(guò)具體的組件,結(jié)合源碼來(lái)講解:

    MembershipService

    一個(gè)集群包含若干成員,要對(duì)這些成員進(jìn)行管理就必須要有一張包含所有成員的列表,當(dāng)要對(duì)某個(gè)節(jié)點(diǎn)做操作時(shí)通過(guò)這個(gè)列表可以準(zhǔn)確找到該節(jié)點(diǎn)的地址進(jìn)而對(duì)該節(jié)點(diǎn)發(fā)送操作消息。

    Tribes的設(shè)計(jì)是基于同等節(jié)點(diǎn)之間的通信,并不存在主節(jié)點(diǎn)選舉的問(wèn)題,每個(gè)節(jié)點(diǎn)都是相等的關(guān)系。它具備自動(dòng)發(fā)現(xiàn)節(jié)點(diǎn),即新節(jié)點(diǎn)加入要通知集群其他成員更新成員列表,讓每個(gè)節(jié)點(diǎn)都能及時(shí)更新成員列表,每個(gè)節(jié)點(diǎn)通過(guò)交換機(jī)各自都維護(hù)一份集群成員表,且他們隔一段時(shí)間向交換機(jī)組播自己節(jié)點(diǎn)消息,即心跳操作。

    集群的成員列表在 SimpleTcpCluster 類的成員屬性 memberOnameMap 里:


    Tribes通過(guò) registerMember()、unregisterMember()方法,實(shí)現(xiàn)集群節(jié)點(diǎn)的注冊(cè)和卸載,更新各自節(jié)點(diǎn)的集群節(jié)點(diǎn)列表

    舉個(gè)例子:

    一個(gè)Tomcat集群,一開(kāi)始有兩個(gè)節(jié)點(diǎn),A和B。

    A和B各自分別都創(chuàng)建一個(gè)節(jié)點(diǎn)信息發(fā)射器和節(jié)點(diǎn)信息接收器,讓他們運(yùn)行于獨(dú)立的線程中。發(fā)射器用于向組內(nèi)發(fā)送自己節(jié)點(diǎn)的消息,而接收器則用于接收其他節(jié)點(diǎn)發(fā)送過(guò)來(lái)的節(jié)點(diǎn)消息并進(jìn)行處理。

    A和B都定時(shí)向交換機(jī)發(fā)送心跳檢測(cè),如果超過(guò)一定時(shí)間交換機(jī)沒(méi)有接受到某個(gè)節(jié)點(diǎn)的心跳,則會(huì)給所有節(jié)點(diǎn)發(fā)送信息,然后所有節(jié)點(diǎn)更新自己的集群節(jié)點(diǎn)列表,將他移除。

    如果這時(shí)候集群新增了節(jié)點(diǎn)C,節(jié)點(diǎn)C的Tomcat會(huì)通過(guò)發(fā)射器,向交換機(jī)發(fā)送自己的訊號(hào),交換機(jī)負(fù)責(zé)傳遞,告訴每個(gè)節(jié)點(diǎn),更新他們各自的集群節(jié)點(diǎn)列表,新增這個(gè)節(jié)點(diǎn)。


    Tomcat提供了一個(gè)接口 MembershipService。我們可以通過(guò)他,獲取集群環(huán)境中的其他成員節(jié)點(diǎn),獲取各個(gè)節(jié)點(diǎn)的信息。

    例如,下面的這些方法:


    等等方法 …

    ChannelSender

    剛才也說(shuō)了,Tribes是個(gè)通訊框架,那就肯定有消息的發(fā)送者,ChannelSender 就充當(dāng)這個(gè)角色。
    ChannelSender 是個(gè)接口,Tomcat中他有一個(gè)唯一的實(shí)現(xiàn)類 ReplicationTransmitter ,他是作為消息發(fā)送的實(shí)際執(zhí)行者。

    這個(gè)類最核心的方法是 sendMessage(),他一目了然,先獲取發(fā)送消息的承載類,然后利用他,傳入集群環(huán)境的其他節(jié)點(diǎn),分別對(duì)他們發(fā)送消息。


    MultiPointSender接口的實(shí)現(xiàn)類有多個(gè),實(shí)現(xiàn)了sendMessage()方法,作為實(shí)際的發(fā)送執(zhí)行者,有以下幾個(gè),分別處理不同的場(chǎng)景。

    ChannelReceive

    消息的傳遞,有發(fā)送者,自然也有接受者,ChannelReceive就充當(dāng)這個(gè)接收者。他負(fù)責(zé)接收處理其他節(jié)點(diǎn)從消息發(fā)送通道發(fā)送過(guò)來(lái)的消息。

    本質(zhì)其實(shí)是每個(gè)節(jié)點(diǎn)暴露一個(gè)端口作為服務(wù)端,去監(jiān)聽(tīng)客戶端,接受客戶端發(fā)送的消息;而每個(gè)節(jié)點(diǎn)又充當(dāng)客戶端,去連接集群中其他節(jié)點(diǎn)的服務(wù)端,發(fā)送自己的消息。

    ChannelSender就是充當(dāng)客戶端的,而ChannelReceiver充當(dāng)服務(wù)端。

    從ChannelReceive的類繼承關(guān)系中可以看到,Tribes的消息接受端,有兩種處理的方式,NIO和BIO。


    BIO:
    同步阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程,常使用于連接數(shù)目比較小且固定的架構(gòu),程序簡(jiǎn)單易理解,但是性能較低。

    NIO:
    同步非阻塞,基于Channel(通道)和Buffer(緩沖區(qū))進(jìn)行操作的,數(shù)據(jù)總是從通道讀取到緩沖區(qū)中,或者從緩沖區(qū)寫(xiě)入到通道中,Selector(選擇器)用于監(jiān)聽(tīng)多個(gè)通道事件,因此使用單個(gè)線程就可以監(jiān)聽(tīng)多個(gè)客戶端通道,能夠大大提升處理的效率。

    NioReceiver 這個(gè)接收端處理類中值得一提的是,他引入了任務(wù)池的概念,在加載這個(gè)類時(shí),已經(jīng)創(chuàng)建好任務(wù)池,把接收任務(wù)提前定義好放入內(nèi)存中,當(dāng)接收到來(lái)自集群節(jié)點(diǎn)的消息時(shí),可直接獲取使用而不用再實(shí)例化。

    ChannelInterceptor

    通道攔截器。為了提高系統(tǒng)的可擴(kuò)展性和靈活性,實(shí)現(xiàn)在應(yīng)用層提供對(duì)源消息統(tǒng)一處理,Tribes在通道中引入通道攔截器。

    通過(guò)類繼承關(guān)系可以看到,目前Tomcat提供了以下幾個(gè)通道攔截器:

    這些具體的攔截器都是繼承類 ChannelInterceptorBase,源碼跟蹤發(fā)現(xiàn),啟動(dòng)時(shí),會(huì)通過(guò)通道的任務(wù)池executor,遍歷集群成員列表,分別啟動(dòng)一個(gè)任務(wù)線程,去執(zhí)行攔截器。

    MembershipListener和ChannelListener

    為了更清晰更好地劃分職責(zé),Tribes設(shè)計(jì)了IO層和應(yīng)用層,IO層專心負(fù)責(zé)網(wǎng)絡(luò)傳輸方面的邏輯處理,把接收到的數(shù)據(jù)往應(yīng)用層傳送,應(yīng)用層發(fā)送的數(shù)據(jù)也是通過(guò)此IO層發(fā)送。

    而應(yīng)用層的處理入口,就是MembershipListener和ChannelListener。

    從名字可以看出,這里用了監(jiān)聽(tīng)器模式,在信息傳輸時(shí),觸發(fā)安裝好的監(jiān)聽(tīng)器,使之執(zhí)行監(jiān)聽(tīng)器里面的處理邏輯。這些事件主要包含了集群成員的加入和退出、消息報(bào)文接收完畢等信息。所以分成兩類監(jiān)聽(tīng)器:

    MembershipListener:跟集群成員的變化相關(guān)

    ChannelListener:是跟集群消息接收發(fā)送相關(guān)

    MembershipListener接口有兩個(gè)抽象方法:



    當(dāng)集群環(huán)境添加了節(jié)點(diǎn)時(shí),其他節(jié)點(diǎn)就會(huì)接收信息,這個(gè)信息進(jìn)來(lái)Tomcat的通道時(shí),就會(huì)觸發(fā)監(jiān)聽(tīng)器的 memberAdded()方法(memberAdded一直監(jiān)聽(tīng)者集群環(huán)境過(guò)來(lái)的而信息),就會(huì)根據(jù)當(dāng)前節(jié)點(diǎn)Tomcat執(zhí)行的模式,去調(diào)用對(duì)應(yīng)的方法,執(zhí)行具體的處理邏輯。

    移除節(jié)點(diǎn)也一樣。

    ChannelListener接口有兩個(gè)抽象方法:


    當(dāng)消息通過(guò)通道傳遞進(jìn)來(lái)時(shí),觸發(fā)監(jiān)聽(tīng)器的 messageReceived(),根據(jù)當(dāng)前節(jié)點(diǎn)Tomcat執(zhí)行的模式,去調(diào)用對(duì)應(yīng)的方法,執(zhí)行具體的處理邏輯。

    而accept()方法,則是由通道調(diào)用,以確定監(jiān)聽(tīng)器是否將處理此消息。

    五、集群的Session同步

    Session的同步,是指在一個(gè)Tomcat的集群環(huán)境下,不借助其他第三方的組件,由Tomcat內(nèi)部通訊機(jī)制,實(shí)現(xiàn)各個(gè)節(jié)點(diǎn)之間的Session信息的同步。

    如果集群中有一個(gè)Tomcat實(shí)例的會(huì)話變了,它會(huì)通過(guò)會(huì)話管理器將改變的動(dòng)作消息封裝成消息然后調(diào)用集群對(duì)象Cluster,由Tribes將會(huì)話同步請(qǐng)求發(fā)出去。集群中會(huì)話同步的過(guò)程中,通信過(guò)程是以ClusterMessage為對(duì)象進(jìn)行傳輸?shù)?#xff0c;將實(shí)際的會(huì)話數(shù)據(jù)載體SessionMessageImpl序列化,進(jìn)行傳輸,到其他Tomcat實(shí)例的時(shí)候會(huì)反序列化,消息由Tribes接收之后向Cluster上傳。最后達(dá)到會(huì)話管理器,它根據(jù)動(dòng)作消息同步會(huì)話

    • Ssession同步的配置

    每個(gè)節(jié)點(diǎn)的Tomcat,在配置了集群的前提下,在 標(biāo)簽里面,加入 標(biāo)簽,配置上 ClusterSessionListener。

    針對(duì)ClusterSessionListener源碼進(jìn)行分析:
    里面代碼不多,主要就一個(gè)方法messageReceived(),用于接受集群環(huán)境傳輸過(guò)來(lái)的要同步的session信息。

    通過(guò)ClusterMessage封裝會(huì)話信息,傳進(jìn)來(lái),解析這是對(duì)應(yīng)哪個(gè)context應(yīng)用的會(huì)話

    拿到集群管理器里面對(duì)應(yīng)的context,將會(huì)話信息設(shè)置進(jìn)去

    消息的接收方法messageDataReceived(),源碼跟蹤進(jìn)去,最終到了DetalManager類的messageReceived()。

    從下圖可以看到,根據(jù)接收的會(huì)話消息實(shí)體里面的類型,分別做不同的處理,例如會(huì)話信息的創(chuàng)建、修改、移除、獲取 …

    我們點(diǎn)進(jìn)去created方法,看看創(chuàng)建會(huì)話的代碼細(xì)節(jié)

    這個(gè)方法是創(chuàng)建一個(gè)新的session會(huì)話信息,可以看到,他先將全局的接受計(jì)數(shù)器屬性 +1,然后創(chuàng)建一個(gè)空的session,把sessionId,會(huì)話信息等設(shè)置進(jìn)去。

    這個(gè)方法是集群的其他節(jié)點(diǎn)請(qǐng)求獲取所有session信息的處理方法,他會(huì)把當(dāng)前節(jié)點(diǎn)tomcat的所有session信息查詢出來(lái),然后通過(guò)集群發(fā)送出去。

    其他剩余的session修改、移除、獲取等的方法,這里就不看了,代碼不復(fù)雜。

    六、集群的Session共享

    前面說(shuō)的session同步,是在Tomcat集群環(huán)境下,實(shí)現(xiàn)每個(gè)節(jié)點(diǎn)的會(huì)話信息的同步,從而可以使集群的整體,無(wú)論訪問(wèn)哪個(gè)節(jié)點(diǎn),獲取到的會(huì)話信息都是一樣的。

    但是這種方案,有很大的弊端,他是不斷通過(guò)網(wǎng)絡(luò)IO去發(fā)起請(qǐng)求,接收請(qǐng)求,去不斷地在每個(gè)節(jié)點(diǎn)執(zhí)行同步,不止存在網(wǎng)絡(luò)的延遲,還會(huì)有性能的損耗。所以自從這種方案誕生,就沒(méi)幾個(gè)開(kāi)發(fā)者愿意使用這種方式。

    大部分人,還是會(huì)選擇使用session的共享。共享,就是每個(gè)節(jié)點(diǎn)使用的session,都是來(lái)自同一個(gè)地方,拿數(shù)據(jù)寫(xiě)數(shù)據(jù)都是在同一個(gè)地方操作,這樣就不需要同步數(shù)據(jù),防止出現(xiàn)數(shù)據(jù)延遲,數(shù)據(jù)不一致的問(wèn)題。

    但是Tomcat原生是不支持這種共享方式的,所以有一位開(kāi)源作者,開(kāi)發(fā)了一個(gè)用第三方中間件redis來(lái)存儲(chǔ)會(huì)話信息的的實(shí)現(xiàn)方案。

    這種方案他的實(shí)現(xiàn)方式看以下圖:


    他跟用Redis做緩存的方式是一樣的,只不過(guò)他現(xiàn)在是用Redis來(lái)存儲(chǔ)Session會(huì)話的信息,說(shuō)白了,他們其實(shí)是一個(gè)意思,只是如果原本項(xiàng)目代碼寫(xiě)了會(huì)話的方式,這里可以直接,用會(huì)話共享,實(shí)現(xiàn)項(xiàng)目的集群部署。

    • 使用方法

    把 tomcat8.5-redis-session-manager.jar 和相關(guān)的依賴包,放到Tomcat安裝目錄下的lib目錄。

    然后修改Tomcat的 context.xml 配置文件,在 標(biāo)簽里面加入如下配置:

    • 原理講解

    從上面的修改配置中我們看到,引入了兩個(gè)類:

    com.s.tomcat.redissessions.RedisSessionHandlerValve

    com.s.tomcat.redissessions.RedisSessionManager

    從他們的包名可以看出來(lái)他們都是來(lái)自我們給Tomcat引入的第三方依賴包。這個(gè)包主要實(shí)現(xiàn)的功能是:

    在Tomcat里添加一個(gè)閥門(mén),當(dāng)session內(nèi)容變動(dòng)時(shí),觸發(fā)這個(gè)閥門(mén),向配置好的redis插入數(shù)據(jù),把session的信息同步到redis里面,在具體的應(yīng)用中,當(dāng)我們通過(guò)代碼獲取當(dāng)前的Session時(shí),調(diào)用的是這個(gè)包里面的方法而不是Tomcat的方法,然后這個(gè)方法會(huì)去redis,獲取我們想要的會(huì)話信息并返回,這個(gè)過(guò)程,應(yīng)用的程序編寫(xiě)者是完全不感知的,他和原本的獲取Tomcat會(huì)話信息的代碼是一致的。

    下面出現(xiàn)的所有代碼截圖,都是來(lái)自tomcat8.5-redis-session-manager.jar的代碼

    我們打開(kāi) RedisSessionManager 類的源碼看到,他繼承了Tomcat的抽象類ManagerBase,這個(gè)類就是用來(lái)管理信息的一個(gè)父類,他的子類將用來(lái)承載例如Session的會(huì)話數(shù)據(jù)的管理。

    而RedisSessionManager繼承了ManagerBase,自然也繼承了他管理會(huì)話的能力,然后他重寫(xiě)了里面的 createSession()、findSession()、add()、remove()等等方法,利用redis,去實(shí)現(xiàn)會(huì)話信息的創(chuàng)建和獲取。

    我們以createSession()方法來(lái)探索一下,可以看到,他先通過(guò)配置文件的redis連接信息,獲取redis的連接,以sessionId作為key在redis創(chuàng)建一條作為session的父級(jí)數(shù)據(jù)。

    下面這兩段代碼,他創(chuàng)建了一個(gè)內(nèi)部類似Session管理的對(duì)象(RedisSession繼承了Tomcat的StandardSession,StandardSession就是Tomcat的Session信息承載類),然后將會(huì)話信息設(shè)置進(jìn)去,調(diào)用saveInternal()方法,把對(duì)象的信息寫(xiě)進(jìn)redis。

    然后我們?cè)俜治鱿耭indSession(),剛才那個(gè)方法,通過(guò)第三方的jar包,在里面維護(hù)了一個(gè)充當(dāng)session對(duì)象的類,然后將會(huì)話信息寫(xiě)進(jìn)redis。
    這里,通過(guò)傳入的sessionId,去redis查詢出對(duì)應(yīng)的信息,反序列化成一個(gè)對(duì)象,才封裝成session對(duì)象返回。

    到這里就講解完這個(gè)包如何實(shí)現(xiàn)redis轉(zhuǎn)存Session信息了。


    總結(jié)

    歡迎指出我的錯(cuò)誤!

    總結(jié)

    以上是生活随笔為你收集整理的Tomcat集群应用同步 —— 源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。