nginx,tomcat集群后多个session分配到同一个应用
单节点低负荷的情况下,我们通常把一个WEB应用打成WAR包放WEB应用服务器,如TOMCAT下运行就行了(如图1)。但随着用户量的增加,系统负载日益增长,这时我们通常就会采用多台WEB应用服务器组成集群来分担负荷(tomcat1, tomcat2上同时部署了应用application1; tomcat3上单独部署了应用application3),这时某一用户对同一应用的访问就有可能分配到从不同的TOMCAT访问这个应用(如图2, session1和session2同时访问application1)。假设我们的WEB访问请求都是无状态的,多个后台应用和一个后台应用的处理就没什么区别了,根据每次请求的参数进行相关逻辑处理就行。但通常我们会将用户信息,鉴权的数据等放入session中做用户鉴权, 用户状态数据等基础框架的处理,这时我们每次分配到WEB服务器后台的访问请求就需要记录session状态及数据了,确保每次用户访问,后台从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间是以IP组播发送变更的数据,将数据发送到集群组的其他成员。这里,同一用户访问APPLICATION1的session数据互相有了同步,他们的数据是相同的,就用app1sesson表示。
配置方法是配置 conf/server.xml 文件中的 Manager ,Channel,以及WEB.XML的distributable 属性。
修改 tomcat 的 conf 目录下的 context.xml 文件:
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:localhost:11211 n2:localhost:11212"
failoverNodes="n2"
requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync="false"
sessionBackupTimeout="100"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
copyCollectionsForSerialization="false" />
以上是以 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
2. 采用 memcached session manager 共享session。
这里, tomcat1和tomcat2产生的session1和session2 在 session mananger 的管理下,都使用的是缓存中的共享session,访问应用时这样传到application1应用的session就是图中的共享session.
3.nginx+redis+tomcat集群部署实现session共享
redis 实现:
网址:https://github.com/jcoleman/tomcat-redis-session-manager
同样修改 tomcat 的 conf 目录下的 context.xml 文件:
以上是以 1.2 版为例子,需要用的 jar 包:
tomcat-redis-session-manager-1.2-tomcat-6.jar
jedis-2.1.0.jar
commons-pool-1.6.jar
Tomcat配置(tomcat7)
1.将tomcat-redis-session.jar, jedis-2.7.2.jar ,commons-pool2-2.4.1.jar放入所有tomcat的lib中
2.配置所有tomcat/conf/context.xml文件添加如下内容,配置
session共享
<?xml version='1.0' encoding='utf-8'?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- tomcat-redis-session
共享配置 -->
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="localhost"
port="6379"
database="0"
maxInactiveInterval="60" />
</Context>
换种写法:
首先,是配置tomcat,使其将session保存到redis上。有两种方法,也是在server.xml或context.xml中配置,不同的是memcached只需要添加一个manager标签,而redis需要增加的内容如下:(注意:valve标签一定要在manager前面。)
<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" />
<Manager className="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可以保持共享了。
4.测试
session共享(需要在tomcat中放置一个简单web项目)
启动redis
启动nginx
启动所有tomcat 访问:http://localhost/9999
不停的刷新页面,发现页面的sessionID不变;关闭某个tomcat继续刷新页面,发现sessionID
也不变。说明环境配置成功
所有需要的资源会打包一起