对于大型电商的架构来说,Session是不得不仔细考虑的一个点,而Tomcat作为大型架构中应用的比较多的应用来说,实现方案较之PHP,不知道好了多少。好了,废话不多说,先就上个干货。
Tomcat-Session保持常用方式:
StandardManager:
Tomcat7的默认会话管理器,针对非集群环境单台Tomcat服务器进行会话管理,当Tomcat正常关闭的时候,这些会话相关的数据会被写入磁盘上的一个名叫SESSION.ser的文件,并在Tomcat下次启动时读取此文件。正常关闭能持久,但是非正常关闭,Session会丢失。
PersistentManager
当一个会话长时间处于空闲状态时会被写入到swap中,这对于内存资源比较吃紧的应用环境来说比较有用(强烈建议自己测试)。可以将session存放在local file中,也可以存储在MySQL Server中。
DeltaManager:
用于Tomcat集群的会话管理器,就是所谓的session复制集群。工作模式是,当前服务器在保存session的时候还会将session同步到集群中其他的所有节点,只有2-3台Tomcat比较理想,多了就急剧消耗性能,不过这个是非常常用的。
BackupManager:
上面那种的改进版,也是session复制,但是不会复制到所有的节点,只会复制到指定的节点,需要结合pacemaker的资源粘性和倾向性,或者Rhcs的failover domain。会话还需要绑定在一个服务器,这种实现方式比较麻烦。有时间单独写一篇blog
Mysql Session Server:
使用Memcache做Session服务器
DeltaManager:
一、配置
1.在Tomcat配置的egine或者host中加入对应的官方DeltaManager配置:
配置文件位置:http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html
,这个是Tomcat 7的,如果版本不同之需要将url中的tomcat-7-0
改成对应的就好。对了,Tomcat 7版本的少了一些东西,具体在配置文件会指出
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
//Cluster:专用于配置Tomcat集群的元素,可用于Engine和Host容器中。在用于Engine
//容器中时,Engine中的所有Host均支持集群功能。
//Manger:定义Session集群所使用的Manager,也就是上面介绍的那些集群方式
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
//Channel:用于Cluster中给集群中同一组中的节点定义通信“信道”
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
//Membership:用于Channel中配置同一通信信道上节点集群组中的成员情况,即监控加入当前集群
//组中的节点并在各节点间传递心跳信息,而且可以在定长时间未接受到某成员的心跳信息时将其移除。
address="228.0.0.4" //组播地址
port="45564" //组播端口
frequency="500" //发送频率
dropTime="3000"/> //超时时间
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
//Receiver:用于Channel定义某节点如何从其它节点的Sender接收复制数据
address="auto" //可以写IP地址
port="4000" //端口
autoBind="100" //同时允许100个连接
selectorTimeout="5000" //监测超时时间
maxThreads="6"/> //线程数
//用于Channel中配置“复制信息”的发送器,实现发送Session至集群中的其它节点。
<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>
2.在tomcat配置文件的engine段加入jvmRoute
<Engine name="Catalina" defaultHost="localhost" jvmRote="Tomcat21">
3.将默认App配置文件拷贝过来,然后进行修改
# mkdir /web/webapps/testapp/WEB-INF/
# cp /usr/local/tomcat/conf/web.xml /web/webapps/testapp/WEB-INF/
//编译安装是从这个地方拷贝,rpm安装请自行处理
# vim /web/webapps/testapp/WEB-INF/web.xml
<distributable/> //将这句加入其中,基本随便找个位置就行
4.前端调度器配置: <Proxy balancer://tomcatCluster> BalancerMember http://192.168.100.21:8080 loadfactor=1 route=tomcat21 BalancerMember ajp://192.168.100.22:8009 loadfactor=1 route=tomcat22 </Proxy>
<VirtualHost *:80>
ServerName itcys.top
ProxyVia Off
ProxyPreserveHost On
ProxyPass ~ .*\.(html|css|js|peng|jpg|png|gif)$ !
ProxyPass / balancer://tomcatCluster/
ProxyPassReverse / balancer://tomcatCluster/
<Location />
Order Allow,Deny
Allow from all
</Location>
</VirtualHost>
二、效果:
虽然服务器在不停的调度,但是Session还是不变。如果不是太消耗资源,这个无疑是一个非常好的Sessin集群方案。
StandardManager:
本来这个是自带的,应该放在最上面的,但是为了演示集群环境和非集群环境的不同,这个还是放在下面。
一.非集群环境测试
1.tomcat配置(只需要一台就好):
# cp /usr/local/tomcat/conf/server.xml /usr/local/tomcat/conf/server.xml.bak
# vim /usr/local/tomcat/conf/server.xml
<!--
将Cluster段删除,或者用这样的方式注释掉
-->
# service tomcat restart
2.修改访问机器的hosts,将虚拟主机IP指向修改过了的Tomcat主机。
# sudo vim /etc/hosts
3.查看Session
4.重启Tomcat测试机器
# service tomcat restart
5.查看Session:
6.停止Tomcat,查看SESSION.ser文件
# service tomcat stop
# cat /usr/local/tomcat/work/Catalina/itcys.top/_/SESSIONS.ser
??srjava.lang.Integer⠤???8Ivaluexrjava.lang.Number???
???xpsrjava.lang.Long;??̏#?Jvaluexq~V?
?sq~V?qsrjava.lang.Boolean? r?՜??Zvaluexpsq~sq~V? 30D7EE2352A6AB55C2A13DBAFBC00
上面那条PATH对应: $CATATINA_HOME/work/Catalina/<virtualHostName>/<webappName>/SESSIONS.ser
二.集群环境测试:
先查看Session:
# service tomcat stop //停止21节点Tomcat
因为是Session复制集群,所以所有节点上面Session都相同,Session并无变化。
# service tomcat stop //停止22节点Tomcat
# service tomcat start //将2个节点的tomcat都启用
Session发生变化,效果为Session Cluster中,如果没有幸存的主机(保存所有Session的主机),Session就会被刷新。对应起来就是Session Manager只能存在一种。
memcache实现session保持:
http://repo1.maven.org/maven2/de/javakaffee/msm/
1.安装部署Memcache Server
因为使用Memcached的场景比较多,所以我就写了个ansible paly book。我的其他文章中应该写了memcached的安装方法,所以这里就不再提了。因为我这里没有给出安装方法,所以那个memcahed服务脚本文件也不提供了。其实究其原因还是因为我写的是blog,不是部署document。因为没有生产环境的经验,所以我希望读者借鉴我的blog就好,真正生产环境还是不要对着我的blog做,拿走思路和方法就行。
[root@Ansible ansible]# tree memcache/
memcache/
├── configFile
│ └── memcached
├── memcached.retry
├── memcached.yaml
└── packages
├── libevent-2.0.20-stable.tar.gz
└── memcached-1.4.15.tar.gz
2 directories, 5 files
[root@Ansible ansible]# cat memcache/memcached.yaml
# Sourece install memcached-1.4.15
# Author: Chen Yanshan Mail: [email protected] Blog: itcys.top
# Version 1.0 time: 2016-07-24
- hosts: memcacheServers
remote_user: root
vars:
libevent: libevent-2.0.20-stable.tar.gz
memcache: memcached-1.4.15.tar.gz
tasks:
- name: Copy libevent source file
copy: src=/ansible/memcache/packages/ dest=/tmp/
- name: Unpack libevent source file
shell: tar -xzvf /tmp/ creates=~/libevent-2.0.20-stable
- name: Install plugin prerequisites
yum: pkg= state=present
with_items:
- gcc
- name: Configure
shell: chdir=~/libevent-2.0.20-stable ./configure --prefix=/usr/local/libevent create=~/libevent-2.0.20-stable/Makefile
- name: Make and make install
shell: chdir=~/libevent-2.0.20-stable make && make install create=/usr/local/libevent/bin/
- name: Libevent so ldconfig
shell: echo "/usr/local/libevent/lib" > /etc/ld.so.conf.d/libevent.conf&& /sbin/ldconfig creates=/etc/ld.so.conf.d/libevent.conf
- name: Copy memecache source file
copy: src=/ansible/memcache/packages/ dest=/tmp/
- name: UnPack memcache source file
command: tar -xzvf /tmp/
- name: Configure
shell: chdir=~/memcached-1.4.15 ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent creates=/tmp/memcached-1.4.15/Makefile
- name: Make and make install
shell: chdir=~/memcached-1.4.15 make && make install
- name: Copy memcached service scripts
copy: src=/ansible/memcache/configFile/memcached dest=/etc/rc.d/init.d/ mode=0755
- name: add chkconfig list
command: chkconfig --add memcached
加入memcached之后。现在的架构就会变成这样:
MSM–memcached session manager是一个高可用的Tomcat session共享解决方案,除了可以从本机内存快速读取Session信息(仅针对黏性Session)外,同时可使用memcached存取Session,以实现高可用。 对于非黏性Session,memcached直接存储session。
黏性session原理介绍:安装在Tomcat上的MSM使用本机内存保存session,和StandardManager一样。另外,当一个请求结束时,session会被送回Memcached进行备份。当下一次请求开始时,本地Session可用,直接服务,请求结束后,session又被送回Memcached备份。 当集群中的一个Tomcat挂掉,下一次请求会被路由到其他Tomcat上。负责处理此此请求的Tomcat并不清楚Session的信息。此时它会从Memcached查找该Session,更新该Session并将其保存在本机内容。此次请求结束,session被修改,送回Memcached备份
memcached-session-manager项目地址,http://code.google.com/p/memcached-session-manager/
安装文档:https://code.google.com/archive/p/memcached-session-manager/wikis/SetupAndConfiguration.wiki
先给依赖库(将这些包放到$CATALINA_HOME/lib/
下面):
$ tree memcached-session-manager/
memcached-session-manager/
├── javolution-5.5.1.jar
├── memcached-session-manager-1.8.2.jar
├── memcached-session-manager-tc7-1.8.2.jar
├── msm-javolution-serializer-1.8.2.jar
└── spymemcached-2.10.2.jar
下载地址:http://repo1.maven.org/maven2/de/javakaffee/msm/
如同下载地址中给出的的5个库一样,msm有5种序列化方式,所以下载的时候包的名称一定一定要对应,像上面tree种第三个包,tc7,这个也需要和tomcat版本对应。
Tomcat配置(就是之前的配置修改一些内容):
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
//------------------------------------------------------------------------------------
<Host name="itcys.top" appBase="/web/webapps"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="testapp" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.100.31:11211,n2:192.168.100.32:11211"
//修改这个地方的配置
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
//javolution序列化方式,和上面给出的包一致
/>
</Context>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="itcys.top_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
//------------------------------------------------------------------------------------
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
这个配置文件的含义就不解释了,配置内容很多,示例中给出的很少,有兴趣或者生产环境使用的是msm的朋友,建议去看下上面给出的官方文档,那里面解释的比较详细
测试(测试文件就直接使用之前提供了的):
过程我就不一一列出来了,反正来去就这2张图。但是Session保持和高可用都达到了,而且全部Tomcat同时关机再启动Session还是没有问题
基本上Tomcat Session HA就差不多了,虽然讲的不是很全面,但是我相信上面的内容对很多对Tomcat不是非常熟悉的运维工作者来说是肯定够用了,再讲下去也没太大的意义,看文档效果一样。