天天看點

Tomcat 叢集中 Session 共享的方法

來自  : http://www.cnblogs.com/zhangdie/p/5730194.html  

單節點低負荷的情況下,我們通常把一個WEB應用打成WAR包放WEB應用伺服器,如TOMCAT下運作就行了(如圖1)。但随着使用者量的增加,系統負載日益增長,這時我們通常就會采用多台WEB應用伺服器組成叢集來分擔負荷(tomcat1, tomcat2上同時部署了應用application1; tomcat3上單獨部署了應用application3),這時某一使用者對同一應用的通路就有可能配置設定到從不同的TOMCAT通路這個應用(如圖2, session1和session2同時通路application1)。假設我們的WEB通路請求都是無狀态的,多個背景應用和一個背景應用的處理就沒什麼差別了,根據每次請求的參數進行相關邏輯處理就行。但通常我們會将使用者資訊,鑒權的資料等放入session中做使用者鑒權, 使用者狀态資料等基礎架構的處理,這時我們每次配置設定到WEB伺服器背景的通路請求就需要記錄session狀态及資料了,確定每次使用者通路,背景從session取出的資料是一緻的。

Tomcat 叢集中 Session 共享的方法
Tomcat 叢集中 Session 共享的方法

    到這裡,我們已經可以清楚的看到,叢集環境下,某一使用者請求通路APPLICATION1,第一次請求被NGINX轉發到TOMCAT1,産生了SESSION1,這時,APPLICATION1存了某一資料進SESSION1。随後,該使用者進行第二次請求,這時,NGINX将該請求轉發到TOMCAT2,這時TOMCAT2産生了一個新的SESSION2來通路APPLICTION1,如果這時APPLICTION1從SESSION中取剛存入的資料,因為SESSION2是TOMCAT2新産生的,并不是剛才存入資料的SESSION1,就會取不到我們想要的資料.

    是以,很自然的,我們就想到需要保持session1和session2的一緻性。 

    而保持session1和session2的一緻性有兩種很明顯的方法,一種是保持session1和session2中的資料一緻,二是讓session1和session2成為一個session,即如果同一使用者通路applcation1, tomcat1和tomcat2産生的是一個共享的session。下面就介紹下這兩種處理方式.

 1. TOMCAT間的 session複制。

    顧名思義,就是把一台TOMCAT上session發生變更的時候, 将變更的資料分發給其他TOMCAT。如圖3

Tomcat 叢集中 Session 共享的方法

     tomcat間是以IP多點傳播發送變更的資料,将資料發送到叢集組的其他成員。這裡,同一使用者通路APPLICATION1的session資料互相有了同步,他們的資料是相同的,就用app1sesson表示。

     配置方法是配置 conf/server.xml 檔案中的 Manager ,Channel,以及WEB.XML的distributable 屬性。 網上已有很多配置介紹,這裡就不啰嗦了。

2. 采用 memcached session manager 共享session。

Tomcat 叢集中 Session 共享的方法

    這裡, tomcat1和tomcat2産生的session1和session2 在 session mananger 的管理下,都使用的是緩存中的共享session,通路應用時這樣傳到application1應用的session就是圖中的共享session.

    這種共享session方案可采用google的memcached session manager, 注意下載下傳時對應TOMCAT版本。 它以memcached作為緩存,安裝時所有tomcat節點需要安裝memcached-session-manager。支援sticky session 和 non-sticky session。大概原理是當一個請求結束時,session會被送回Memcached進行備份。當下一次請求開始時,本地Session可用,直接服務,請求結束後,session又被送回Memcached備份。如果下一次請求會被路由到其他Tomcat上。負責處理此此請求的Tomcat并不清楚Session的資訊。此時它會從Memcached查找該Session,更新該Session并将其儲存在本機内容。此次請求結束,session被修改,送回Memcached備份。如下圖:

Tomcat 叢集中 Session 共享的方法

配置方法網上也有很多介紹,主要是修改 tomcat下 conf/server.xml, memcachedNodes可指定多個memcached節點, 逗号隔開。

<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"

  memcachedNodes="n1:localhost:11211"

  requestUriIgnorePattern=".*\.(png|gif|jpg|css|js){1}quot;"

  sessionBackupAsync="false"

  sessionBackupTimeout="1800000"

  copyCollectionsForSerialization="false"

  transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"

/>

如是非粘性,配置 sticky="false":

<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"

  memcachedNodes="n1:localhost:11211"

   sticky="false"

  requestUriIgnorePattern=".*\.(png|gif|jpg|css|js){1}quot;"

  sessionBackupAsync="false"

  lockingMode="uriPattern:/path1|/path2"

  transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"

/>

來自 : http://blog.csdn.net/qh_java/article/details/45955923

前兩種均需要使用 memcached 或redis 存儲 session ,最後一種使用 terracotta 伺服器共享。

建議使用 redis,不僅僅因為它可以将緩存的内容持久化,還因為它支援的單個對象比較大,而且資料類型豐富,

不隻是緩存 session,還可以做其他用途,一舉幾得啊。

1、使用 filter 方法存儲

這種方法比較推薦,因為它的伺服器使用範圍比較多,不僅限于tomcat ,而且實作的原理比較簡單容易控制。

可以使用memcached-session-filter

官方網址:http://code.google.com/p/memcached-session-filter/

官方介紹:解決叢集環境下javaweb容器session共享,使用filter攔截器和memcached實作。在tomcat 6和websphere8測試通過,現網并發2000,日PV量1100萬。

暫不支援sessionevent包括create destory 和 attribute change

東西很不錯,體積很小,不過這個東東要和spring 一起使用,而且要求存儲到 memcached 的對象要實作 java 的序列化接口

大家也知道,java本身的序列化性能也很一般。

我将其簡單擴充了一下,不再依賴spring ,并且利用 javolution 實作序列化,緩存的對象不再有限制。

暫時沒有發現 redis的實作,後面将自己實作使用 redis 存儲并且序列化使用 kyro ,詳細情況有時間再單獨寫出來。

2、使用 tomcat sessionmanager 方法存儲

這種方法伺服器隻能使用 tomcat,但網上有針對 memcached 和 redis 實作,直接配置就行了。

memcached 實作:

網址:http://code.google.com/p/memcached-session-manager/

修改 tomcat 的 conf 目錄下的context.xml 檔案:

 &lt;ManagerclassName="de.javakaffee.web.msm.MemcachedBackupSessionManager"   

 memcachedNodes="n1:localhost:11211n2:localhost:11212"   

 failoverNodes="n2"   

 requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"   

 sessionBackupAsync="false"   

 sessionBackupTimeout="100"   

 transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"   

 copyCollectionsForSerialization="false"    /&gt;

以上是以 1.3 版為例子,需要用的jar 包:

memcached-session-manager-1.3.0.jar

msm-javolution-serializer-1.3.0.jar

javolution-5.4.3.1.jar

memcached-2.4.2.jar

redis 實作:

網址:https://github.com/jcoleman/tomcat-redis-session-manager

同樣修改 tomcat 的 conf目錄下的 context.xml 檔案:

&lt;ValveclassName="com.radiadesign.catalina.session.RedisSessionHandlerValve"/&gt;

&lt;ManagerclassName="com.radiadesign.catalina.session.RedisSessionManager"

        host="localhost"

        port="6379"

        database="0"

        maxInactiveInterval="60"/&gt;

以上是以 1.2 版為例子,需要用的jar 包:

tomcat-redis-session-manager-1.2-tomcat-6.jar

jedis-2.1.0.jar

commons-pool-1.6.jar

3、使用 terracotta 伺服器共享

這種方式配置有點複雜,大家到網上搜尋一下吧。

以上配置成功後,前端使用 nginx進行負載均衡就行了,同時使用 Gzip 壓縮 和 靜态檔案緩存。

以下是執行個體:

一、nginx+tomcat+memcached  (依賴架包下載下傳)

1.memcached配置:(v1.4.13)

節點1(192.168.159.131:11444)

節點2(192.168.159.131:11333)

2.tomcat配置

tomcat1(192.168.159.128:8081)

tomcat2(192.168.159.128:8082)

3.nginx安裝在192.168.159.131。

      首先,是配置tomcat,使其将session儲存到memcached上。有兩種方法:

方法一:在server.xml中配置。

找到host節點,加入

<ContextdocBase="/var/www/html" path="">

        <ManagerclassName="de.javakaffee.web.msm.MemcachedBackupSessionManager"

               memcachedNodes="n1:192.168.159.131:11444n2:192.168.159.131:11333"

                requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"

                sessionBackupAsync="false"sessionBackupTimeout="3000" 

               transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"

               copyCollectionsForSerialization="false"/>

</Context>

方法二:在context.xml中配置。

找到Context節點,在context中加入

        <ManagerclassName="de.javakaffee.web.msm.MemcachedBackupSessionManager"

                memcachedNodes="n1:192.168.159.131:11444"

               requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"

                sessionBackupAsync="false"sessionBackupTimeout="3000"

                transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"

               copyCollectionsForSerialization="false" />

      其次,配置nginx,用于測試session保持共享。

upstream  xxy.com {

      server   192.168.159.128:8081 ;

      server   192.168.159.128:8082 ;

}

log_format  www_xy_com '$remote_addr - $remote_user [$time_local] $request '

               '"$status"$body_bytes_sent "$http_referer"' 

              '"$http_user_agent" "$http_x_forwarded_for"';

server

{

      listen  80;

      server_name  xxy.com;

location/ {

               proxy_pass        http://xxy.com;

               proxy_set_header   Host             $host;

               proxy_set_header   X-Real-IP        $remote_addr;

               proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

      }

access_log  /data/base_files/logs/www.xy.log  www_xy_com;

}

最後,将你的應用放到兩個tomcat中,并依次啟動memcached、tomcat、nginx。通路你的nginx,可以發現兩個tomcat中的session可以保持共享了。

二、nginx+tomcat+redis   (依賴架包下載下傳)

1.redis配置(192.168.159.131:16300)(v2.8.3)

2.tomcat配置

tomcat1(192.168.159.130:8081)

tomcat2(192.168.159.130:8082)

3.nginx安裝在192.168.159.131。

       首先,是配置tomcat,使其将session儲存到redis上。有兩種方法,也是在server.xml或context.xml中配置,不同的是memcached隻需要添加一個manager标簽,而redis需要增加的内容如下:(注意:valve标簽一定要在manager前面。)

配置和memcached 一樣 找到Context節點,在context中加入

<ValveclassName="com.radiadesign.catalina.session.RedisSessionHandlerValve"/>

<ManagerclassName="com.radiadesign.catalina.session.RedisSessionManager"

         host="192.168.159.131"

         port="16300"

         database="0"

         maxInactiveInterval="60"/>

其次,配置nginx,用于測試session保持共享。

upstream  redis.xxy.com {

      server   192.168.159.130:8081;

      server   192.168.159.130:8082;

}

log_format  www_xy_com '$remote_addr - $remote_user [$time_local] $request '

               '"$status"$body_bytes_sent "$http_referer"' 

              '"$http_user_agent" "$http_x_forwarded_for"';

server

{

      listen  80;

      server_name redis.xxy.com; 

location/ {

               proxy_pass        http://redis.xxy.com;

               proxy_set_header   Host             $host;

               proxy_set_header   X-Real-IP        $remote_addr;

               proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

      }

access_log  /data/base_files/logs/redis.xxy.log  www_xy_com;

}

最後,将你的應用放到兩個tomcat中,并依次啟動redis、tomcat、nginx。通路你的nginx,可以發現兩個tomcat中的session可以保持共享了。