MSM实现tomcat集群中session共享的高可用

1、测试环境概述

    采用两台linux x64主机,主机上分别安装memcached与tomcat,memcached提供key/value的存储服务,tomcat提供jsp程序的web容器,两主机关闭iptables,关闭selinux。
    主机规划如下:
主机1
IP地址:192.168.0.201
主机名:nod2.tes.com   别名:nod2
安装服务:jdk、tomcat、memcached
主机2
IP地址:192.168.0.202
主机名:nod3.tes.com   别名:nod3

安装服务:jdk、tomcat、memcached
    简易拓扑如下:
        <tomcat1>         <tomcat2>
                 . \   / .
                  .  X  .
                 . /   \ .
       <memcached1>      <memcached2>
2、MSM简介

     MSM 全称为Memcached Session Manager(Memcached会话管理器),是tomcat的用户session信息存放在像memcached这样的兼容key/value存储里的高可用解决方案,这里常使用的key/value服务有memcached与membase两种。
2.1、MSM的特性MSM的特性
a、支持tomcat 6,tomcat 7,tomcat 8
b、支持sticky session或no-sticky session
c、无单点故障
d、tomcat故障转移
e、memcached故障转移
f、附带串行化插件
g、支持异步session存储,拥有更快的性能
....
2.2、MSM要解决的问题
    假如有一个web app运行在一个tomcat集群中,前端通过apache的mod_jk或mod_proxy实现tomcat的负载均衡集群,你想实现用户session的故障转移,从而达到用户session信息的不丢失。在前边的博文中已提出了一个“集群/session复制”的解决方案( http://www.iyunv.com/thread-68321-1-1.html ),此种方案有一个缺点,当tomcat集群节点多余4或5个时,集群的性能就可能达到一个瓶颈,因其内部的session复制的实现是通过组播实现,对网络的压力很大,官方建议此种方案只适合小规格集群的环境中。而 MSM 能真正的解决这个问题,是session会话共享的一个可伸缩性解决方案, MSM 是把用户的session信息存放在memcached中,假如一个tomcat节点死掉,其他的tomcat节点将接管工作并从后端的memcached服务器中取得之前的session信息,这保证了用户会话不会丢失,而后端的memcached的节点可以不只一个,配置多个memcached节点又保证了memcached的单点故障。
2.3、MSM的工作原理
     MSM 支持两种工作模式,sticky session和no-sticky session(从memcached-session-manager-1.4.0开始支持no-sticky session)。
sticky session模式:
    安装了 MSM 的tomcat会优先使用本机内存保存session,当一个请求结束后, MSM 会把session发送到memcached节点上存放以作备份,第二次请求时,如果本地有session就直接返回,第二次请求结束,把session修改后的信息更新到后端的memcached服务器,以这样的方式来保持本地的session与memcached上的session同步。当这个tomcat节点宕机时,那么用户的下一次请求就会被前端的负载均衡器路由到另一个tomcat节点上,而这个节点上并没有这个用户的session信息,这个节点就从memcached服务器上去读取session,并把session保存到本地的内存,当请求结束,session又被修改,再送回到memcached进行存放备份。结合下边的图就更能理解 MSM 基于sticky session的工作原理。
wKiom1VZ8xPTBIllAAF63FF9JOc518.jpg 
注:图片来自网络
另外,当后端配置了多台memcached时, MSM 在更新session信息时会同时向多个memcached节点更新session,当一个memcached节点故障时,tomcat可以从选择一个正常工作的memcached节点读取session信息来发送给用户的浏览器,让其重置session信息,这样,memcached也达到了高可用的目的。
no-sticky session模式:
    假设后端配置了两个memcached服务器,memcached1和memcached2,在这种配置的配置方法中没有发现有能设置哪个memcached是主,哪个是备,所以我猜想是 MSM 自身来确定哪个是主,哪个是备,为了描述no-sticky sessio的工作过程,假设memcahced1是主,memcached2是备。当请求到来时, MSM 从memcached2(备)上读取session信息,如果没有就从memcached1(主)上读取,如果有那就读取到本地,如果没有那就在本地创建session,当请求结束时,把本地的session信息写回到memcached1和memcached2,并且要清除本地的session。结合下边的图,更能理解此模式的工作原理:
wKioL1VZ9LLT-G5nAAFyEE1HhJo565.jpg 
注:图片来自网络
3、环境搭建
3.1、memcached安装
    在yum源中的memcached的版本也比较新,所以直接采用yum进行安装,如下:
[iyunv@nod2 ~]# yum -y install memcached
[iyunv@nod2 ~]# service memcached start

在nod3上依然采取yum安装,略。
3.2、jkd与tomcat安装配置
1
2
3
4
5
6
7
8
[iyunv@nod2 msm]# pwd
/root/software/msm
[iyunv@nod2 msm]# ls
apache-tomcat-7.0.62.tar.gz  jdk-8u45-linux-x64.rpm  msm_kryo_serializers
[iyunv@nod2 msm]# ls msm_kryo_serializers/
asm-3.2.jar                memcached-session-manager-1.8.3.jar      msm-kryo-serializer-1.8.3.jar
kryo-1.04.jar              memcached-session-manager-tc7-1.8.3.jar  reflectasm-1.01.jar
kryo-serializers-0.11.jar  minlog-1.2.jar                           spymemcached-2.11.1.jar



上边的这些jar包分为两类,一类是关于 msm 的包:
memcached-session-manager-1.8.3.jar

memcached-session-manager-tc7-1.8.3.jar
另一类是kryo序列化的jar包:
asm-3.2.jar        msm -kryo-serializer-1.8.3.jar  kryo-serializers-0.11.jar  minlog-1.2.jar  spymemcached-2.11.1.jar kryo-1.04.jar     reflectasm-1.01.jar
这些包的下载地址在这里 http://code.google.com/p/memcach ... tupAndConfiguration  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[iyunv@nod2 msm]# rpm -ivh jdk-8u45-linux-x64.rpm
[iyunv@nod2 msm]# /usr/java/latest/bin/java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
[iyunv@nod2 msm]# vim /etc/profile.d/java.sh
JAVA_HOME=/usr/java/latest
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH
[iyunv@nod2 msm]# source /etc/profile.d/java.sh
[iyunv@nod2 msm]# tar xf apache-tomcat-7.0.62.tar.gz -C /usr/local/
[iyunv@nod2 msm]# cd /usr/local/
[iyunv@nod2 local]# ln -sv apache-tomcat-7.0.62 tomcat
[iyunv@nod2 local]# /usr/local/tomcat/bin/catalina.sh version
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Server version: Apache Tomcat/7.0.62
Server built:   May 7 2015 17:14:55 UTC
Server number:  7.0.62.0
OS Name:        Linux
OS Version:     2.6.32-358.el6.x86_64
Architecture:   amd64
JVM Version:    1.8.0_45-b14
JVM Vendor:     Oracle Corporation
[iyunv@nod2 local]# vim /etc/profile.d/tomcat.sh
CATALINA_HOME=/usr/local/tomcat
PATH=$CATALINA_HOME/bin:$PATH
export CATALINA_HOME PATH
[iyunv@nod2 local]# source /etc/profile.d/tomcat.sh



为tomcat提供一个启用脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[iyunv@nod2 ~]# vim /etc/rc.d/init.d/tomcat
#!/bin/sh
#Description: This shell script manage apache tomcat.
#Author: zhaochj
#Time: 2015-5-18
#Version: 1.0
case $1 in
    "start")
        /usr/local/tomcat/bin/catalina.sh start
        ;;
    "stop")
        /usr/local/tomcat/bin/catalina.sh stop
        ;;
    "restart")
        /usr/local/tomcat/bin/catalina.sh stop
        sleep 3
        /usr/local/tomcat/bin/catalina.sh start
        ;;
    *)
        echo "Usage:`basename $0` {start|stop|restart}"
        exit 1
        ;;
esac
[iyunv@nod2 ~]#  chmod +x /etc/rc.d/init.d/tomcat



在nod3上以同样的方法安装jdk与tomcat。
两个节点都启动tomcat,测试一下能否进入默认界面,经测试,两个节点都能进入tomcat的默认界面,但在catalina.out日志输出中发现有如下提示:
1
2
3
4
[iyunv@nod2 tomcat]# tail /usr/local/tomcat/logs/catalina.out
......
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
....



这是因为tomcat可以整合本地的apr,使用tomcat处理静态资源时性能更好,要想启用tomcat的此功能,进行如下配置:
1
2
3
4
5
6
7
8
9
[iyunv@nod2 bin]# pwd
/usr/local/tomcat/bin
[iyunv@nod2 bin]# tar xf tomcat-native.tar.gz
[iyunv@nod2 bin]# cd tomcat-native-1.1.33-src/jni/native/
[iyunv@nod2 native]# ./configure --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/java/jdk1.8.0_45
[iyunv@nod2 native]# make && make install
[iyunv@nod2 native]# ls /usr/local/apr/lib/
libtcnative-1.a  libtcnative-1.la  libtcnative-1.so  libtcnative-1.so.0  libtcnative-1.so.0.1.33  pkgconfig
[iyunv@nod2 native]# cp /usr/local/apr/lib/libtcnative-1.so /usr/lib64/



重启tomcat,再观察输出日志中有
INFO: Loaded APR based Apache Tomcat Native library 1.1.33 using APR version 1.3.9.
May 18, 2015 5:03:00 PM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]
则证明apr的问题已解决。
接着创建虚拟主机及增加jvmRoute:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[iyunv@nod2 tomcat]# vim /usr/local/tomcat/conf/server.xml
把<Engine name="Catalina" defaultHost="localhost">修改成<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
在“nod3”上把<Engine name="Catalina" defaultHost="localhost">修改成<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
在<Engine>容器中增加一个<Host>容器,内容如下:
<Engine>
.....
<Host name="nod2.test.com"  appBase="/tomcat/app"
            unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="mysite"/>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="nod2_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
......
</Engine>



在"nod3"上增加以下内容:
1
2
3
4
5
6
7
8
9
10
11
<Engine>
.....
<Host name="nod3.test.com"  appBase="/tomcat/app"
            unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="mysite"/>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="nod3_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
......
</Engine>



接下来为tomcat提供一个工程(nod2与nod3上创建过程一样):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#创建一个工程目录mysite
[iyunv@nod2 ~]# 
mkdir -pv /tomcat/app/mysite
[iyunv@nod2 ~]# cp -r /usr/local/tomcat/webapps/host-manager/WEB-INF/ /tomcat/app/mysite
[iyunv@nod2 ~]# vim /tomcat/app/mysite/index.jsp #一个测试所用的工程,nod3上把此文件中的“nod2”修改为“nod3”
<%@ page language="java" %>
<html>
<head><title>nod2</title></head>
<body>
  <h1><font color="red">nod2</h1>
  <table align="centre" border="1">
   <tr>
    <td>Session ID</td>
  <% session.setAttribute("abc","abc"); %>
    <td><%= session.getId() %></td>
   </tr>
   <tr>
    <td>Created on</td>
    <td><%= session.getCreationTime() %></td>
   </tr>
  </table>
</body>
</html>
两个节点都配置好后,启动tomcat,测试:
[iyunv@nod2 ~]# service tomcat start
[iyunv@nod3 ~]# service tomcat start



wKiom1VZ82bApdh4AADJeQb--Ak907.jpg 
wKiom1VZ83mxFoD5AADD7p8vkX8660.jpg 
3.3、MSM sticky session + kryo模式的配置
在进行配置之前,把 MSM 和序列化需要的包准备好。
1
2
3
4
5
6
[iyunv@nod2 msm]# pwd
/root/software/msm
[iyunv@nod2 msm]# ls msm_kryo_serializers/
asm-3.2.jar                memcached-session-manager-1.8.3.jar      msm-kryo-serializer-1.8.3.jar
kryo-1.04.jar              memcached-session-manager-tc7-1.8.3.jar  reflectasm-1.01.jar
kryo-serializers-0.11.jar  minlog-1.2.jar                           spymemcached-2.11.1.jar



把上边的所有jar包放在$CATALINA_HOME/lib目录内:
1
[iyunv@nod2 msm]# cp msm_kryo_serializers/* /usr/local/tomcat/lib/



接着更新<Context>元素,建议最好不要在$CATALINA_HOME/conf/server.xml定义,这样太具有侵略性,对整个tomcat都有效。应配置$CATALINA_HOME/conf/context.xml文件。
在配置tomcat相关的配置文件时,应该先停止tomcat服务,再做修改。
把以下代码加入到context.xml中,两个节点都要进行修改:
1
2
3
4
5
6
7
8
9
<Context> 
.....
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="memcached1:192.168.0.201:11211,memcached2:192.168.0.202:11211"
             failoverNodes="memcached1"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/> 
.....
</Context>



failoverNodes="memcached1"告诉 MSM 把session信息优先存放在memcached2中,只有当memcached2不可用时,才把session存放在memcached1中,memcached1是一个失效转移的节点。
在nod2上设置failoverNodes="memcached1",在nod3上设置failoverNodes="memcached2",这不是必须,我只是用来验证两个节点到底是把session优先存放在哪个memcached上。
文件修改好后,启动tomcat服务,分别访问两个节点进行测试:
wKioL1VZ9RfTaX-9AADa8I0KZes153.jpg 
wKioL1VZ9S6TVJqvAAC09L9HFaY118.jpg 
看上边两个节点的seesion的返回信息,nod2把session存放在了memcached2上,此节点上的failoverNodes="memcached1";nod3上刚是把session存放在memcached1上,它的failoverNodes="memcached2"。
现在我把nod2上的memcached关闭,再来看下两个节点的返回信息。
1
2
[iyunv@nod2 webapps]# service memcached stop
Stopping memcached:                                        [  OK  ]



wKioL1VZ9VaRVCkxAADZcYdDsPM084.jpg 
nod3把session的存放节点重定向到了memcached2上了,我再启动nod2上的memcached服务,nod3页面不会自动再定向回memcached1,我再关闭nod2上的memcached服务,访问我们的两个站点,Session ID中的memcached1或memcached2都能正常的切换,切换后前边的session id也是保持不变的,说明用户的session信息真正的保存在了memcached服务器上。
3.4、MSM no-sticky session + kryo模式的配置

基于no-sticky seesion + kryo的模式,只需要把要增加在context.xml的代码更换成下边的即可
1
2
3
4
5
6
7
8
9
10
11
<Context>
....
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="memcached1:192.168.0.201:11211,memcached2:192.168.0.202:11211"
             sticky="false"
             sessionBackupAsync="false"
             lockingMode="uriPattern:/path1|/path2"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
......
</Context>



经测试,在no-sticky session模式下,后端的memcached各节点没有主、备之分,完全由 MSM 自行决定使用哪个memecached节点,用户的session信息由 MSM 写入到各个memcached中,只要有一个memcached节点正常工作,那用户的session信息就不会丢失。
4、思考与总结
    至此,此博文介绍完了利用 MSM 来构建一套可伸缩的高可用 session共享 集群,此博文是参考了官方文档和网络上的资料,再加上不断的摸索搭建出来的,在做环境测试时有个细节值得注意,起初在启用、停止tomcat服务时,我没有在意日志的输出,只是查看监听的端口是否在监听“8080”端口,而且访问也是正常的,但当我不经意去查看日志输出时,发现日志给予我们好多细节,且还有些错误,当一些错误发生时,tomcat还能正常的访问,如果是在生产环境下会有隐患的,所以在搭建环境,调度程序时,在程序的启动、停止时都要不断的监视日志输出信息,确保环境搭建好后,日志中不会有错误信息,如果有警告也要仔细分析,此信息的产生由来,是否会带来隐患等。
    这次环境搭建好后,在关闭tomcat时,日志输出中还有以下的信息:
SEVERE: The web application [/docs] appears to have started a thread named [Memcached IO over {MemcachedConnection to /192.168.0.202:11211 /192.168.0.201:11211} - SHUTTING DOWN (informed client)] but has failed to stop it. This is very likely to create a memory leak.
通过google也没有得到什么解决方案,只是说这个警告信息不是什么应用程序所报的信息,但最好还是不要有。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值