Tomcat 通过 Memcached 实现 Session 会话共享
1、MSM 项目地址
Memcached-Session-Manager 项目地址 Github
Memcached-Session-Manager 项目地址 Google
2、准备工作
2.1 MSM 相关 jar 包下载
### 下载如下jar文件至各tomcat节点的tomcat安装目录下的lib目录中
### 其中的${version}要换成你所需要的版本号
### tc${6,7,8}要换成与tomcat版本相同的版本号
# 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
2.2 MSM 不同场景的相关 jar 包下载
MSM-Installation and Configuration-WIKI-PAGE-相关 jar 包下载
2.3 MSM 不同场景的配置模版
MSM-Installation and Configuration-WIKI-PAGE-配置模版查看
2.4 相关 jar 包下载
3、实验拓扑
4、Tomcat 和 Memcached 部署
4.1 软件安装
### 安装 Tomcat ###
# yum install tomcat.noarch tomcat-admin-webapps.noarch tomcat-docs-webapp.noarch tomcat-webapps.noarch -y
### 安装 Memcached ###
# yum install memcached -y
4.2 Tomcat -1 配置
4.2.1Tomcat-1 增加的测试页
[root@Tang-1 ~]# mkdir -pv /usr/local/tomcat/webapps/test/WEB-INF/{classes,lib}
[root@Tang-1 ~]# vim /usr/local/tomcat/webapps/test/index.jsp
[root@Tang-1 ~]# cat /usr/local/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
<html>
<head><title>Tomcat-Tang-1</title></head>
<body>
<h1><font color="red">Tang-1</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("Tang","Tang"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
4.2.2 Tomcat-1 server-xml 文件配置
[root@Tang-1 ~]# vim /etc/tomcat/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="Tomcat-Tang-1">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/test" docBase="/usr/local/tomcat/webapps/test" reloadable="true">
</Context>
</Host>
</Engine>
4.2.3 Tomcat-1 服务启动
[root@Tang-1 ~]# systemctl start tomcat
[root@Tang-1 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 100 :::8009 :::*
LISTEN 0 100 :::8080 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 1 ::ffff:127.0.0.1:8005 :::*
4.2.4 Tomcat-1 测试页面访问
4.3 Tomcat-2 配置
4.3.1 Tomcat-2 增加的测试页
[root@Tang-2 ~]# mkdir -pv /usr/local/tomcat/webapps/test/WEB-INF/{classes,lib}
[root@Tang-2 ~]# vim /usr/local/tomcat/webapps/test/index.jsp
[root@Tang-2 ~]# cat /usr/local/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
<html>
<head><title>Tomcat-Tang-2</title></head>
<body>
<h1><font color="purple">Tang-2</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("Tang","Tang"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
4.3.2 Tomcat-2 server-xml 文件配置
[root@Tang-2 ~]# vim /etc/tomcat/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="Tomcat-Tang-2">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/test" docBase="/usr/local/tomcat/webapps/test" reloadable="true">
</Context>
</Host>
</Engine>
4.3.3 Tomcat-2 服务启动
[root@Tang-2 ~]# systemctl start tomcat
[root@Tang-2 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 100 :::8009 :::*
LISTEN 0 100 :::8080 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 1 ::ffff:127.0.0.1:8005 :::*
4.3.4 Tomcat-2 测试页面访问
4.4 Tomcat memcached 配置
4.4.1 Tomcat-1
[root@Tang-1 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.209 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-1 ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="128"
OPTIONS="-t 8 -f 1.1 -U 0"
[root@Tang-1 ~]# systemctl start memcached
[root@Tang-1 ~]# ss -tnlp | grep memcached
LISTEN 0 128 *:11211 *:* users:(("memcached",pid=9166,fd=46))
LISTEN 0 128 :::11211 :::* users:(("memcached",pid=9166,fd=47))
4.4.2 Tomcat-2
[root@Tang-2 ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.209 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang-2 ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="128"
OPTIONS="-t 8 -f 1.1 -U 0"
[root@Tang-2 ~]# systemctl start memcached
[root@Tang-2 ~]# ss -tnlp | grep memcached
LISTEN 0 128 *:11211 *:* users:(("memcached",pid=9166,fd=46))
LISTEN 0 128 :::11211 :::* users:(("memcached",pid=9166,fd=47))
5、Nginx 配置
5.1 conf 文件配置
[root@Tang ~]# ipinfo
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.141.252 netmask 255.255.255.0 broadcast 172.16.141.255
[root@Tang ~]# vim /etc/nginx/nginx.conf
http {
upstream tomcatservers {
server 172.16.141.209:8080;
server 172.16.141.253:8080;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
location / {
}
location /test/ {
proxy_pass http://tomcatservers;
}
}
}
[root@Tang ~]# systemctl start nginx
[root@Tang ~]# ss -tnlp | grep nginx
LISTEN 0 128 *:80 *:* users:(("nginx",pid=19610,fd=6),("nginx",pid=19609,fd=6),("nginx",pid=19608,fd=6),("nginx",pid=19607,fd=6),("nginx",pid=19606,fd=6))
LISTEN 0 128 :::80 :::* users:(("nginx",pid=19610,fd=7),("nginx",pid=19609,fd=7),("nginx",pid=19608,fd=7),("nginx",pid=19607,fd=7),("nginx",pid=19606,fd=7))
5.2 客户端访问
如上,在配置 memcached-session-manager 会话共享之前,访问 http://172.16.141.252/test 的请求会轮询负载到 tomcat-1 和 tomcat-2 两个节点上,并且 session id 会随着页面的刷新而改变,即此时还没有实现 session 会话共享。
6、Tomcat 通过 Memcached 实现 Session 会话共享
6.1 准备工作
- 把第二节中下载的相关 jar 包放置在各 Tomcat 节点的 Tomcat 安装目录下的 lib 目录中。
- 下来进行序列化 Tomcat 配置,序列化 Tomca t配置的方法有很多种:java默认序列化tomcat 配置、javolution 序列化 tomcat 配置、xstream 序列化 tomcat 配置、flexjson 序列化 tomcat 配置和 kryo 序列化 tomca t配置。推荐使用 kryo 序列化 tomcat 的效率最高,所以这里只介绍 kryo 序列化。
6.2 Tomcat 节点的 MSM 配置
[root@Tang-1 ~]# vim /etc/tomcat/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="Tomcat-Tang-1">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/test" docBase="/usr/local/tomcat/webapps/test" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:172.16.141.209:11211,n2:172.16.141.253:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
/>
</Context>
</Host>
</Engine>
[root@Tang-2 ~]# vim /etc/tomcat/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="Tomcat-Tang-2">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/test" docBase="/usr/local/tomcat/webapps/test" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:172.16.141.209:11211,n2:172.16.141.253:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
/>
</Context>
</Host>
</Engine>
6.3 参数说明
故障转移配置节点(failoverNodes),不能使用在Non-Sticky模式,多个使用空格或逗号分开,配置某个节点为备份节点。当其他节点都不可用时才会存储到备份节点,适用于sticky模式(即一台tomcat,多台memcached)
-
memcachedNodes:必选项,memcached的节点信息,多个memcached节点,中间需要使用空格
-
failoverNodes=“n2”:表示当前 session 保持到 n1 的 memcached 节点上
## 当其他节点都不可用时才会存储到备份节点,官方建议配置为和tomcat同服务器的节点 ## 理由如下: ### 假如有两台服务器m1,m2,其中m1部署tomcat和memcached节点n1,m2部署memcached节点n2 ### 如果配置tomcat的failoverNodes值为n2或者不配置,则当服务器m1挂掉后n1和tomcat中保存的session会丢失,而n2中未保存或者只保存了部分session,这就造成 部分用户状态丢失 ### 如果配置tomcat的failoverNodes值为n1,则当m1挂掉后因为n2中保存了所有的session,所以重启tomcat的时候用户状态不会丢失 ### 为什么n2中保存了所有的session? 因为failoverNodes配置的值是n1,只有当n2节点不可用时才会把session存储到n1,所以这个时候n1中是没有保存任何session的
-
lockingMode:可选值,默认none,只对 non-sticky 有效
-
requestUriIgnorePattern:可选值,制定忽略那些请求的 session 操作,一般制定静态资源,如 css,js 一类的
-
sessionBackupAsync:可选值,默认 true,是否异步的方式存储到 memcached
-
sessionBackupTimeout:可选项,默认100毫秒,异步存储 session 的超时时间
6.4 重启 Tomcat 服务后,进行页面访问
- 1、访问http://172.16.141.252,按 ctrl+F5 强刷页面,发现 session 信息会变,但是 session id 不会改变,说明 session 实现了共享
- 2、关闭 Mem-node1 节点的 memcached 服务,继续访问页面,发现 session id 保存到了n2 这个 memcached 节点上了,但是 session id 任然没有改变,说明 session 已共享. 也就是说,关闭 memcached 集群中的任意一个节点访问页面,session id 都不会改变.即可以实现 memcached 故障转移
- 3、关闭 tomcat-node1 和 tomcat-node2 中的任意一个节点的 tomcat 服务,继续访问页面,发现前端从 nginx 负载过来的请求达到未关闭的 tomcat 节点上,session id 都不会改变,依然共享中!即可以实现 tomcat 故障转移
- 4、特别提示:如果memcached session manager的会话共享配置后,重启tomcat服务没有报错,但是访问页面的时候报错,页面访问失败,如下在logs/catalina.out日志里发现的错误:
SEVERE [http-nio-8080-exec-1] org.apache.coyote.http11.AbstractHttp11Processor.process Error processing request java.lang.NoSuchFieldError: attributes