概述
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服務,進行測試:
調度至不一樣的節點上,session信息沒有發上變化,測試完成。
基於memcached+MSM實現session服務器
實驗拓撲
實驗環境:
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
利用上一個案例配置的負載均衡和添加的測試頁面進行測試,測試結果與上述一致。.................^_^