session共享
如果在实际应用部署中,只部署单台tomcat,那么不需要考虑session共享,因为无论怎么访问,session肯定来自tomcat部署的这台机器上,当我们的应用需要两个或者两个以上的tomcat服务器来支撑时,就需要考虑session共享的问题了,如果不考虑,假设用户在一台tomcat的应用上登录了,如果负载均衡让我们的访问出现在了另外的一台机器上,那么由于这两台机器并没有做session共享,就需要用户再次登录,这就造成很不友好的用户体验。
session共享的方案有多种,有基于memcached,redis的实现方式,也可以让两台服务器上存储session的位置做文件同步,这样session也可以是一致的,但是会有延时的问题,无论哪种实现方式,他们的原理都相同。即将用户登录的session保存在同一个地方,无论用户最终访问的是哪一个tomcat服务器,都会保证session一致。
这里介绍tomcat+redis实现session共享:需要两个tomcat,一个redis服务器即可。tomcat可以部署在不同的虚拟机,也可以部署在同一台机器(开启不同的端口)。
具体实施
1、并没有什么官方给出tomcat集群session共享方案的redis实现,但是github上有人实现了tomcat基于redis的session共享。
2、代码中并没有直接支持tomcat8,但是给出了支持tomcat8的修改方法。
具体修改代码:RedisSessionManager.java,修改方法initializeSerializer中的如下部分:
3、自己编译项目打包tomcat-redis-session-manager.jar
可以按照github例子,构建gradle项目,引入commons-pool2-2.3.jar和jedis-2.7.2.jar,tomcat-catalina-8.0.14.jar即可。
最后在项目目录下运行:gradle build即可,构建成功之后,在build/libs目录下会生成tomcat-redis-session-manager.jar。将生成的jar以及commons-pool2-2.3.jar、jedis-2.7.2.jar加入到tomcat/lib目录下。
也可以构建maven项目引入commons-pool2,jedis依赖,修改代码之后,就可以打包。
4、修改tomcat/conf/context.xml配置文件增加Valve,Manager配置。
在context.xml的Context节点下增加如下配置:
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve"/>
port="6379"
database="0"
maxInactiveInterval="60"
/>
注意细节
1、修改context.xml配置文件时需要注意Valve不要写成Value,否则会报错,另外类的名字也是RedisSessionHandlerValve。
10-Sep-2018 20:20:59.747 WARNING [localhost-startStop-1] org.apache.tomcat.util.digester.Digester.endElement No rules found matching 'Context/Value'.
10-Sep-2018 20:20:59.996 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal The session manager failed to start
org.apache.catalina.LifecycleException: Failed to start component [com.orangefunction.tomcat.redissessions.RedisSessionManager[]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5380)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:755)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:731)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1125)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1868)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
2、一定要将Valve配置在Manager之前。
测试
这里我将两个tomcat部署在一个虚拟机上,分别开启端口8080和8090。
编写session测试文件:
webapps/ROOT/session.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
SessionID:<%=session.getId()%>
SessionIP:<%=request.getServerName()%>
SessionPort:<%=request.getServerPort()%>
重启tomcat,在一个浏览器中开启两个tab页,分别访问
http://10.119.9.149:8080/session.jsp
http://10.119.9.149:8090/session.jsp
虽然是访问的两个tomcat,但是他们返回的session却是一致的。这说明session共享已经实现。
我们可以访问redis,看看页面上的sessionid :5DF9262B7C7A929AD081F2F8D4A6A828 保存情况。
[root@server tomcat8080]# /usr/local/bin/redis-cli
127.0.0.1:6379> dbsize
(integer) 1
127.0.0.1:6379> keys *
1) "5DF9262B7C7A929AD081F2F8D4A6A828"
127.0.0.1:6379> get 5DF9262B7C7A929AD081F2F8D4A6A828
"\xac\xed\x00\x05sr\x00Dcom.orangefunction.tomcat.redissessions.SessionSerializationMetadata\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x01[\x00\x15sessionAttributesHasht\x00\x02[Bxpw\x14\x00\x00\x00\x10\x1c\x1f\xd4\xa1k\x1aq\xd3u\xfbe\xbffJ\x8c\xabxsr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01e\xc6\x9d\xed#sq\x00~\x00\x03\x00\x00\x01e\xc6\x9d\xed#sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexq\x00~\x00\x04\x00\x00\a\bsr\x00\x11java.lang.Boolean\xcd r\x80\xd5\x9c\xfa\xee\x02\x00\x01Z\x00\x05valuexp\x01q\x00~\x00\nsq\x00~\x00\x03\x00\x00\x01e\xc6\x9d\xed#t\x00 5DF9262B7C7A929AD081F2F8D4A6A828sq\x00~\x00\a\x00\x00\x00\x00w\b\x00\x00\x01e\xc6\x9d\xed#"
127.0.0.1:6379>
至此,tomcat+redis session共享方案已经试验完成,需要注意的是配置context.xml文件时,一定要注意不要把Valve写成了Value。避免造成不必要的麻烦。