Tomcat的session集羣和session服務器

概述
css

session的做用html

httpd是無狀態協議,多個http請求之間是沒有關聯的,服務器端也沒法識別哪些請求來自同一個客戶端。爲了解決這一問題,當客戶端第一次訪問時,服務器端會建立一個session來保存這一次的會話信息,而後將sessionID(session的惟一標識符)放置在響應報文的首部發送給客戶端,客戶端再次請求時會攜帶這個sessionID(一般在request的cookie中)表示這屬於哪個會話。
前端

維持session的方式java

在Tomcat實現負載均衡後,客戶端的請求會被調度至不一樣的服務器,session信息每每保存在其中一臺服務器的內存中,若以後的請求被調度至其餘的服務器上,則客戶端沒法訪問到以前的session信息。解決這一問題的方式有3種:
node

1)session綁定,在調度時,將同一個客戶端的請求始終調度至同一臺服務器;web

2)session集羣,將多臺服務器上的session信息實時進行同步;apache

3)session服務器,將全部服務器上的session信息都存放至session服務器。vim


第一種方式能夠在前端的代理服務器上配置相應的參數實現,可是這種方式會影響負載均衡的效果,而且其中的一臺服務器故障了,其上的session信息也會所有丟失。第二種方式經過同步session實現,即每個會話的session信息存在於全部的服務器上,這個不適用於大型的集羣環境。第三種方式是將session信息集中存放至一臺專用的服務器上,例如memcache服務器上,服務器在處理請求時會首先將session信息從memcache同步至本地,而後進行處理。本文介紹第二種和第三種的實現方式。後端


session集羣的實現
tomcat

實驗環境:2個tomcat節點,利用httpd實現負載均衡。

192.168.1.116   #http服務器

192.168.1.106   #tomcat node1

192.168.1.127   #tomcat node2


1)首先配置http服務器實現負載均衡(192.168.1.116上)。

[root@www ~]# vim /etc/httpd/extra/httpd-vhosts.conf
#######全局配置端################
<proxy balancer://lbcluster>
BalancerMember http://192.168.1.106:8080 loadfactor=1 route=a
BalancerMember http://192.168.1.127:8080 loadfactor=1 route=b
#ProxySet stickysession=JSESSIONID      #不作session綁定
ProxySet lbmethod=bytraffic
</proxy>
########虛擬主機的配置##############
<VirtualHost *:80>
    ServerName www.xiaoxiao.com
    ProxyVia Off
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / balancer://lbcluster/
    ProxyPa***everse / balancer://lbcluster/
    <Location /status>
      SetHandler balancer-manager
      Proxypass !
      Require all granted
    </Location>
    <Proxy *>
      Require all granted
    </Proxy>
    <Location  / >
      Require all granted
    </Location>
</VirtualHost>

包含對應文件:

[root@www ~]# vim /etc/httpd/httpd.conf 
........
Include /etc/httpd/extra/httpd-vhosts.conf


2)在每一個tomcat節點上配置server.xml文件,在須要實現session集羣的host中添加以下段落,若如下內容定義在Engine容器中,則表示全部主機均啓用集羣功能。

[root@node1 ~]# vim /usr/local/tomcat/conf/server.xml
.....
        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">
 
          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>
 
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.3.4"
                        port="45564"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>
 
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.3.4"              #監聽的多播地址(最好不要使用默認值)
                        port="45564"                     #監聽的端口
                        frequency="500"                  #每一個多長時間發一次心跳信息(單位毫秒)
                        dropTime="3000"/>                #超時時長(超過這個時間尚未接受到心跳信息,則從Membership中移除該成員)
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="192.168.1.106"            #經過哪一個接口接收數據,若是有多個IP地址,這裏須要指定
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>
 
            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>
 
          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
 
          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>
 
          <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>
.....

若在虛擬機中配置必須指定Receiver段中的address爲本機上某接口的地址。在node2節點上配置時,將該參數改成對應的IP地址(192.168.1.127)。


3)爲指望實現集羣功能的webapp的web.xml文件添加<distributable/>

[root@node1 web]# vim WEB-INF/web.xml 
.....
<web-app .....
.....
  <distributable/>
</web-app>


4)在tomcat的兩個節點上添加測試頁面

node1上(192.168.1.106):

[root@node1 ~]# vim /tomcat/webapps/web/index.jsp 
<%@ page language="java" %>
<html>
  <head><title>Tomcat node1</title></head>
  <body>
    <h1><font color="blue">Tomcat node1</font></h1></p>
    <% session.setAttribute("xiaoxiao.com","xiaoxiao.com"); %>
    <h4>Session_ID:<%= session.getId() %></h4></p>
    <h4>Creat_time:<%= session.getCreationTime() %></h4></p>
  </body>
</html>

node2上(192.168.1.127):

[root@node2 ~]# vim /tomcat/webapps/web/index.jsp 
<%@ page language="java" %>
<html>
  <head><title>Tomcat node2</title></head>
  <body>
    <h1><font color="red">Tomcat node2</font></h1></p>
    <% session.setAttribute("xiaoxiao.com","xiaoxiao.com"); %>
    <h4>Session_ID:<%= session.getId() %></h4></p>
    <h4>Creat_time:<%= session.getCreationTime() %></h4></p>
  </body>
</html>

最後重啓tomcat服務,進行測試:

wKiom1XoVgvibpk0AAEHPhcLEkE091.jpg

wKioL1XoWGKwjfyIAAEh1Koyesc621.jpg

調度至不一樣的節點上,session信息沒有發上變化,測試完成。



基於memcached+MSM實現session服務器

實驗拓撲

wKiom1Xuoqqg5lkOAACYjH5Q_VU347.jpg

實驗環境:

192.168.1.116   #http服務器

192.168.1.106   #tomcat node1

192.168.1.127   #tomcat node2

192.168.1.121,192.168.1.122    #memcached服務器

工做原理:

用戶第一次訪問時,服務器端會建立會話信息,保存在進程中,實時同步至memcache,若下一次調度至其餘節點上,該節點首先會檢查本身的會話區域,若沒有這個用戶的會話,就去memcache中找這個會話信息,而後將這個會話信息從memcache讀到本身的web container中,若會話更新也會馬上同步至memcache中。以後同一個客戶端的某一次請求調度至以前訪問過的節點,該節點會先去memcache中檢查本地的會話信息是否和memcache上的同步,若是不一樣步從memcache讀取新數據覆蓋本身的原有數據。


memcached-session-manager簡介

memcached-session-manager(msm)爲Google提供的一款工具,可以實現將tomcat會話信息保存至memcache中,並在須要時將對應信息讀入web container。它能夠工做在兩種模式下:1)會話有粘性,2)會話無粘性,即前端的代理服務器是否啓用了stickysession(同一客戶端請求代理至同一服務器)。上述的工做原理是工做在會話無粘性的模式下,若在會話有粘性的場景中,當用戶來訪問時,就不須要每次去memcache中檢查會話信息是否是最新的,會話更新後,也不須要將會話信息及時同步至memcache中,能夠節約一些步驟和帶寬。

memcached-session-manager的下載地址,http://code.google.com/p/memcached-session-manager/,該項目基於Java開發,須要使用以下的jar文件(version版本號):

memcached-session-manager-version.jar

memcached-session-manager-tc(6|7|8)-version.jar

spymemcached-version.jar

msm-javolution-serializer-version.jar

javolution-version.jar

其中msm-javolution-serializer爲一款流式化工具,可以將會話信息轉成流式數據存放在memcache上,在讀取時再將其還原,相似的工具備不少,在實現過程當中能夠根據須要選擇不一樣的流式化工具,相關的配置也不一樣,參考官方文檔便可。


實現過程

1)在192.168.1.121,192.168.1.122上安裝memcached

[root@node1 ~]# tar xf libevent-2.0.21-stable.tar.gz
[root@node1 ~]# cd libevent-2.0.21
[root@node1 ~]# ./configure --prefix=/usr/local/libevent
[root@node1 ~]# make && make install
[root@node1 ~]# echo "/usr/local/libevent/lib" > /etc/ld.so.conf.d/libevent.conf
[root@node1 ~]# ldconfig 
#####################################################
[root@node1 ~]#  tar xf memcached-1.4.15.tar.gz 
[root@node1 ~]#  cd memcached-1.4.15
[root@node1 ~]#  ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
[root@node1 ~]#  make && make install

爲memcached提供服務腳本,並配置爲系統服務(腳本能夠copy獲得)

[root@node1 ~]# chmod +x /etc/init.d/memcached
[root@node1 ~]# chkconfig --add memcached
[root@node1 ~]# service memcached start


2)在tomcat node1和node2節點上添加虛擬主機(會話無粘性的模式下):

[root@node1 ~]# vim /usr/local/tomcat/conf/server.xml     
........
<Host name="www.xiaoxiao.com"  appBase="/tomcat/webapps"
            unpackWARs="true" autoDeploy="true">
            <Context path="/web" docBase="web" reloadable="true">
            <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:192.168.1.121:11211,n2:192.168.1.122:11211"
             sticky="false"
             sessionBackupAsync="false"
             lockingMode="uriPattern:/path1|/path2"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
             />
             </Context>
      </Host>

會話有粘性的模式下:

[root@node1 ~]# vim /usr/local/tomcat/conf/server.xml     
........
<Host name="www.xiaoxiao.com"  appBase="/tomcat/webapps"
            unpackWARs="true" autoDeploy="true">
            <Context path="/web" docBase="web" reloadable="true">
            <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:192.168.1.121:11211,n2:192.168.1.122:11211"
             failoverNodes="n1"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
             />
             </Context>
      </Host>

memcachedNodes指定後端的memcache服務器地址和端口,這裏使用了兩個memcache服務器,目的是起到高可用的做用。在保存session信息時須要同時寫到兩個memcache服務器上。


3)將須要的jar文件(類庫)複製到tomcat的lib目錄下:

[root@node1 msm]# ls
javolution-5.5.1.jar                 memcached-session-manager-tc7-1.8.2.jar  spymemcached-2.10.2.jar
memcached-session-manager-1.8.2.jar  msm-javolution-serializer-1.8.2.jar
[root@node1 msm]# cp ./* /usr/local/tomcat/lib/

複製到另一個節點:

[root@node1 msm]# scp ./* 192.168.1.127:/usr/local/tomcat/lib/

而後重啓兩個節點上的tomcat服務:

[root@node1 ~]# service tomcat restart

利用上一個案例配置的負載均衡和添加的測試頁面進行測試,測試結果與上述一致。.................^_^

相關文章
相關標籤/搜索