在上一篇博客中,我们介绍了tomcat自带的cluster组件配置session replication cluster,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13363590.html;session复制集群的原理就是通过多播通信的方式,把节点的session信息发送给集群其他节点;这种session复制集群有一个缺陷,如果后端tomcat server 一旦增多,那么对于后端用于发送session信息的网络会非常拥挤,到达一定的量以后,后端网络就可能瘫痪,这样一来session复制集群就失效了;这其中的原因就是因为各个节点通过多播通信的方式发送session;为了解决这样的问题,我们需要重新想办法把用户的session存起来;常用的解决方案就是找一台服务器或一组服务器用来存用户的session,在用户访问tomcat服务器时,后端tomcat服务器都到我们指定的服务器存取session,这样一来不管前端调度器把请求调度到后端任何一台server上,后端server都会去session服务器上存取session,通过这样的方式,我们可以把用户的信息共享给其他节点;但是我们需要注意一点后端存储session的服务器可能存在单点;常用作为session服务器的有memcached和redis;它们都是键值类型的数据库,不同的是memcached它的值是流式化类型的数据,什么意思呢?也就是说往memcached数据库里存放数据,必须把数据先通过流式化工具编码成数据流,然后存入到memcached中,如果需要取数据出来,它需要再通过流式化工具还原成之前的数据;而redis的值相比memcached的值要丰富很多,它不需要流式化工具将数据编码成数据流,它可以直接存到redis中;
msm是什么?它都全称叫memcached session manager 该组件的作用就是用来解决session共享的;以下是官方介绍:memcached-session-manager是一个tomcat会话管理器,用于将会话保持在memcached或Redis中,用于高可用性,可伸缩性和容错性的Web应用程序。它支持粘性和非粘性配置,并且当前与tomcat 6.x,7.x,8.x和9.x一起使用。对于粘性会话,支持会话故障转移(tomcat崩溃),对于非粘性会话,这是默认设置(默认情况下,不同的tomcat为不同的请求提供会话服务)。此外,通过会话迁移也支持memcached故障转移(memcached崩溃)。也不应有任何单点故障,因此当memcached失败时,会话不会丢失;简单讲就是把tomcat的session信息存放在memcached中,当后端tomcat宕机,它上面存放的session不会丢失,因为都存放到memcached中了,如果memcached是单点,它也支持多节点;其实memcached到多节点不是memcached自身到功能,它是通过使用memcached客户端来实现到,其原理很简单,就是通过客户端把session同时写到多个节点上去,默认情况只有一台memcached工作,当或当节点故障时,它会立即切换到备用节点;
msm搭建
环境说明
名称 | IP地址 | 端口 |
代理服务器nginx | 192.168.16.197 | 80 |
tomcatA+memcached1 | 192.168.16.196 | 8080,11211 |
tomcatB+memcached2 | 192.168.16.198 | 8080,11211 |
首先配置nignx 负载均衡tomcatA和tomcatB,然后在tomcatA和tomcatB上部署一个测试应用,部署的过程和配置可以参考前边的博客,我这里就不阐述了;https://www.cnblogs.com/qiuhom-1874/p/13337003.html;
在tomcatA,tomcatB上安装memcached,并启动memcached
[root@node01 ~]# yum install -y memcached Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: mirrors.aliyun.com * extras: mirrors.aliyun.com * updates: mirrors.aliyun.com base | 3.6 kB 00:00:00 docker-ce-stable | 3.5 kB 00:00:00 epel | 4.7 kB 00:00:00 extras | 2.9 kB 00:00:00 mariadb | 2.9 kB 00:00:00 updates | 2.9 kB 00:00:00 (1/2): epel/x86_64/updateinfo | 1.0 MB 00:00:00 (2/2): epel/x86_64/primary_db | 6.9 MB 00:00:01 Resolving Dependencies --> Running transaction check ---> Package memcached.x86_64 0:1.4.15-10.el7_3.1 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================================================================== Package Arch Version Repository Size ================================================================================================================================== Installing: memcached x86_64 1.4.15-10.el7_3.1 base 85 k Transaction Summary ================================================================================================================================== Install 1 Package Total download size: 85 k Installed size: 176 k Downloading packages: memcached-1.4.15-10.el7_3.1.x86_64.rpm | 85 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : memcached-1.4.15-10.el7_3.1.x86_64 1/1 Verifying : memcached-1.4.15-10.el7_3.1.x86_64 1/1 Installed: memcached.x86_64 0:1.4.15-10.el7_3.1 Complete! [root@node01 ~]# systemctl start memcached [root@node01 ~]# ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:11211 *:* LISTEN 0 128 *:22 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 100 [::]:8009 [::]:* LISTEN 0 128 [::]:11211 [::]:* LISTEN 0 100 [::]:8080 [::]:* LISTEN 0 128 [::]:22 [::]:* LISTEN 0 100 [::1]:25 [::]:* LISTEN 0 1 [::ffff:127.0.0.1]:8005 [::]:* [root@node01 ~]#
提示:在node02上也是上面的操作,启动memcached后,如果能够看到11211端口启动起来了,说明memcached的环境就准备好了;
准备连接memcached所需要用到的jar包
#!/bin/bash wget https://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager/2.3.2/memcached-session-manager-2.3.2.jar wget https://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager-tc7/2.3.2/memcached-session-manager-tc7-2.3.2.jar wget https://repo1.maven.org/maven2/de/javakaffee/msm/msm-kryo-serializer/2.3.2/msm-kryo-serializer-2.3.2.jar wget https://repo1.maven.org/maven2/de/javakaffee/kryo-serializers/0.45/kryo-serializers-0.45.jar wget https://repo1.maven.org/maven2/com/esotericsoftware/kryo/3.0.3/kryo-3.0.3.jar wget https://repo1.maven.org/maven2/com/esotericsoftware/minlog/minlog/1.2/minlog-1.2.jar wget https://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/reflectasm/1.09/reflectasm-1.09.jar wget https://repo1.maven.org/maven2/org/ow2/asm/asm/5.2/asm-5.2.jar wget https://repo1.maven.org/maven2/org/objenesis/objenesis/2.6/objenesis-2.6.jar wget https://repo1.maven.org/maven2/net/spy/spymemcached/2.12.3/spymemcached-2.12.3.jar
提示:我上面是把jar包的连接都整理到一个脚本中,我们可以直接进入到tomcat存放jar的位置,执行脚本,即可把对对应jar包下载到tomcat存放jar包的目录下;通常yum安装到tomcat它的jar存放地是/usr/share/java/tomcat/;msm的文档地址https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration;
提示:这里需要注意点,我们点击对应名称时,它跳转的地址是http,会导致我们访问不到,解决办法就是把http改成https就可以访问到了;上面红框中的jar包是msm中核心包,除了上面的三个包以外,还需要下载序列化的工具包组件,如下
提示:msm序列化工具支持kryo,javolution,xstream,flexjson,根据自己的需求下载对应的序列化工具组件包就行了;
下载好上面的核心包,驱动包,以及序列化工具包,接下来就可以在tomcat中配置连接memcached(tomcatA和tomcatB都要下载上面的jar包)
tomcatA上的配置
提示:以上配置表示,在访问/myapp这个uri时启动MemcachedBackupSessionManager的管理器,这个管理器就是用于存放session的;其中对于这个管理来说,里面有几个属性,memcachedNodes表示指定memcached节点的标识,IP地址和端口,如果是多个节点,节点和节点之间用逗号隔开即可;failoverNodes用于指定失败转移节点的标识,如上配置的是m1,这也就意味m2是活动节点;只有当m2宕机后,m1才会接替m2;requestUriIgnorePattern表示忽略匹配指定模式的请求uri资源;transcoderFactoryClass用于指定序列化工具的类,这个需要同我们之前的序列化工具名称来;比如我们使用的是javolution虚拟化工具,我们需要把写成transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.javolutionTranscoderFactory";
对于tomcatB的server.xml的配置除了jvmRoute的值不一样外,其他配置都是一样的;到此基于msm的session服务器就配置好了;
验证:重启tomcatA和tomcatB,然后用浏览器访问nginx地址,看看通过nginx负载均衡后,访问到后端server是怎么响应客户端的?
访问nginx所在主机地址的/myapp,看看会怎么响应客户端?
首次访问
第二次访问
第三次访问
第四次访问
提示:从上面的访问结果来看,第一次访问会在响应报文添加一个set-cookie的首部。第二次访问时,客户端会通过请求首部cookie把之前的set-cookie的值携带上去访问服务端,此时服务端收到客户端发送过来的cookie,给客户端响应了一个和第一次访问时一样的页面;但是第二次并没有响应首部set-cookie;第三次客户端访问服务端,携带之前的cookie,此时被调度到node02上进行响应了,在响应首部又给客户端了一个set-cookie,和之前的值,变化的只有后面的jvmRoute的标识;页面响应的中的sessionid的值和前一个session的值一样;第四次访问,客户端就把第三次访问响应的set-cookie的值携带上去访问服务端,服务端又给它响应一个set-cookie的值,sessionID的值没有变化,变化的只有后面的jvmRoute的值,此时页面显示的sessionID第三次的页面一样;不一样的是一个是node01响应的,一个是node02响应的,说明调度器在轮询的调度请求;这个和我们之前的session replication cluster 访问结果一样;
把memcached2停掉看看客户端是否还可以访问后端server?
用浏览器访问看看会有什么变化?用刚才访问的浏览器,接着访问
提示:可以看到我们刚才的访问并没有什么影响;
换个浏览器访问或者关闭之前的访问,从新打开浏览器访问
提示:可以看到换了一个浏览器后,我们再次访问后面的memcached就是m1,说明本次访问的session存放在m1上;
从新断开原有的连接,重新启动浏览器访问服务端
提示:可以看到,从新打开浏览器访问,响应的sessionID 还是以前的,只是m2变成了m1;这说明在m1上找到了对应的session,所以当之前访问过服务端的客户端再次访问时,服务端会根据客户端提供的cookie去session服务器上查找,如果session又对应的sessionID,那么就把之前的状态响应给客户端;这同时也说明了m1和m2上都存在之前客户端访问的所有session信息;
恢复m2,看看对应访问是否会从m2上取session?
提示:可以看到当m2存活后,m1又会自动处于备份状态,客户端访问服务端也会从m2上面取session信息;