部署服务器集群离不开Session共享,实现Session共享方式有很多种,对于小型集群(5台服务器内)我们可以采用Session Replication来实现Session共享,这样实现起来容易,又可以
优点:
1,实现简单。
2,不需要使用共享数据库,节点少,降低了故障率。
缺点:
1,同步Session数据造成了网络带宽的开销。只要Session数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
2,每台Web服务器都要保存所有Session数据,如果整个集群的Session数据很多(很多人同时访问网站)的话,每台机器用于保存Session数据的内容占用会很严重。
这里我们使用tomcat8举例说明
测试环境使用两台linux服务器,分别部署tomcat。
服务器1 ip:172.16.0.102
服务器2 ip:172.16.0.104
1,修改tomcat的server.xml文件,增加Cluster配置,如果定义在Engine容器中,则表示对所有主机均启动用集群功能。如果定义在某Host容器中,则表示仅对此主机启用集群功能。此外,需要注意的是,Receiver中的address=”auto”一项的值最好改为当前部署tomcat主机所对应的网络接口的IP地址。配置如下:
<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.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="172.16.0.102"
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.MessageDispatchInterceptor"/>
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.ClusterSessionListener"/>
Cluster>
按此配置好所有的tomcat,除了Receiver中的address,其它值不变。
2,更改web应用程序根目录下“WEB-INF”目录下的web.xml文件,必须添加这个元素
3,在服务器上开启Membership和Receiver使用的端口,使数据可以传输。
完成上述步骤后,挨个启动tomcat。查看tomcat日志,可以看到以下信息。
服务器1的日志
11-Oct-2017 10:24:39.368 INFO [main] org.apache.catalina.ha.tcp.SimpleTcpCluster.startInternal Cluster is about to start
11-Oct-2017 10:24:39.372 INFO [main] org.apache.catalina.tribes.transport.ReceiverBase.bind Receiver Server Socket bound to:/172.16.0.102:4000
11-Oct-2017 10:24:39.379 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.setupSocket Setting cluster mcast soTimeout to 500
11-Oct-2017 10:24:39.381 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Sleeping for 1000 milliseconds to establish cluster membership, start level:4
11-Oct-2017 10:24:40.382 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Done sleeping, membership established, start level:4
11-Oct-2017 10:24:40.383 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Sleeping for 1000 milliseconds to establish cluster membership, start level:8
11-Oct-2017 10:24:41.383 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Done sleeping, membership established, start level:8
11-Oct-2017 10:24:41.384 SEVERE [main] org.apache.catalina.ha.deploy.FarmWarDeployer.start FarmWarDeployer can only work as host cluster subelement!
服务器2的日志
11-Oct-2017 10:25:24.956 INFO [main] org.apache.catalina.ha.tcp.SimpleTcpCluster.startInternal Cluster is about to start
11-Oct-2017 10:25:24.960 INFO [main] org.apache.catalina.tribes.transport.ReceiverBase.bind Receiver Server Socket bound to:/172.16.0.104:4000
11-Oct-2017 10:25:24.967 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.setupSocket Setting cluster mcast soTimeout to 500
11-Oct-2017 10:25:24.970 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Sleeping for 1000 milliseconds to establish cluster membership, start level:4
11-Oct-2017 10:25:25.002 INFO [Membership-MemberAdded.] org.apache.catalina.ha.tcp.SimpleTcpCluster.memberAdded Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{172, 16, 0, 102}:4000,{172, 16, 0, 102},4000, alive=45620, securePort=-1, UDP Port=-1, id={12 42 -64 76 118 -60 72 -75 -116 12 -52 74 71 -108 -100 23 }, payload={}, command={}, domain={}, ]
11-Oct-2017 10:25:25.970 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Done sleeping, membership established, start level:4
11-Oct-2017 10:25:25.971 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Sleeping for 1000 milliseconds to establish cluster membership, start level:8
11-Oct-2017 10:25:25.978 INFO [Tribes-Task-Receiver[Catalina-Channel]-1] org.apache.catalina.tribes.io.BufferPool.getBufferPool Created a buffer pool with max size:104857600 bytes of type: org.apache.catalina.tribes.io.BufferPool15Impl
11-Oct-2017 10:25:26.972 INFO [main] org.apache.catalina.tribes.membership.McastServiceImpl.waitForMembers Done sleeping, membership established, start level:8
11-Oct-2017 10:25:26.972 SEVERE [main] org.apache.catalina.ha.deploy.FarmWarDeployer.start FarmWarDeployer can only work as host cluster subelement!
可以看出两台服务器已经联系上了,再回过头来看第一台服务器的日志,
11-Oct-2017 10:25:25.007 INFO [Tribes-Task-Receiver[Catalina-Channel]-1] org.apache.catalina.tribes.io.BufferPool.getBufferPool Created a buffer pool with max size:104857600 bytes of type: org.apache.catalina.tribes.io.BufferPool15Impl
11-Oct-2017 10:25:25.974 INFO [Membership-MemberAdded.] org.apache.catalina.ha.tcp.SimpleTcpCluster.memberAdded Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{172, 16, 0, 104}:4000,{172, 16, 0, 104},4000, alive=1006, securePort=-1, UDP Port=-1, id={5 52 67 -61 66 126 73 -8 -108 76 20 81 -92 58 27 108 }, payload={}, command={}, domain={}, ]
接下来我们来测试session复制是否成功。在jsp文件中加上
<%= session.getId() %>
这样可以打印出sessionId。
先通过浏览器访问172.16.0.102上的应用,https://172.16.0.102/ljzx/login,从页面上获取sessionId后,在url后加上;jsessionid=SESSION_ID访问172.16.0.104上的应用,https://ljzd.riskraiders.com/ljzx/login;jsessionid=12235D32C91EB8DDF585D0E6B03BB32C
此时如果页面上显示的sessionId和我们传入的sessionId一致,说明session复制已成功。
经过测试发现session复制未成功,查看日志发现以下错误信息
11-Oct-2017 10:47:54.029 SEVERE [http-nio-443-exec-1] org.apache.catalina.ha.session.DeltaManager.requestCompleted Unable to serialize delta request for sessionid [C27AFF6847CB9F76FF93090E55C6A355]
java.io.NotSerializableException: com.srd.ljzd.entity.client.ClientCompany
这是因为保存到session中的对象没有实现Serializable接口,修改相关对象后重新部署测试后可以实现session复制,不过需要注意通过url后加jsessionid值的方式测试的时候,因为cookie中没有jsessionid的,所以第一次请求后服务器会生成一个新的jsessionid给客户端,刷新页面后显示出来的sessionid的值就变了。