1. MSM简介
1.1 MSM(memcached session manager)
- MSM是一个用于解决分布式tomcat环境下session共享问题的开源解决方案
- 以tomcat插件的方式部署在了tomcat服务器上
- 即可以从本机内存快速读取Session信息(黏性Session),也可以使用memcached存储Session,以实现高可用
1.2 MSM的特性
- 支持黏性、非黏性Session
- 无单一故障点
- 可处理tomcat故障转移
- 可处理memcached故障转移
- 插件式session序列化
- 允许异步保存session,以提升响应速度
- 只有当session有修改时,才会将session写回memcached
- JMX管理&监控
1.3 黏性Session和非黏性Session(一般用于tomcat服务集群)
黏性Session:即session sticky,不复制Session会话
- 此模式下同一会话中的请求都被派发到同一个tomcat实例上,这样就无须在多台服务器之间实现session共享了
- 缺点:不能实现failover(故障切换),一旦用户访问的机器挂掉,那么其session就会丢失
非黏性Session:即session replication,复制Session会话
- 此模式下同一个会话中的请求可以被分配到不同的tomcat实例上进行处理
- 此时就需要在不同服务器之间同步、复制session,这样即使一台服务器挂掉了,请求在其他服务器上照样可以访问到session信息
- 缺点:Session复制需要系统资源和网络开销
1.4 MSM解决的问题
问题:
- 若有一个Tomcat集群,使用粘性session,如何应对单点故障?
- 为了应对更多的并发量和可用性,可以不断的增加Tomcat节点,但是单点故障仍旧会是个问题
- 如果使用粘性Session,一个Tomcat故障时,其他Tomcat并不能就干故障Tomcat节点的Session
解决此问题:
- 将粘性Session同时保存在Memcached中,如果单个Tomcat发生故障,集群中的其他Tomcat可以从Memcached中得到Session信息
2. Tomcat和Memcached的故障转移
2.1 Tomcat的故障转移
- MSM安装在tomcat里,tomcat会在本地保留所有会话信息,就如同StandardManager一样
- 一个请求完成后,session会被备份到memcached节点
- 当服务同一会话的下一次请求时,tomcat可以在本地找到这个会话数据
- 同一会话的第二次请求处理完成后,会话数据会更新到memcached节点
- 若处理某个会话的tomcat挂了,那么下次请求会被路由到另一个tomcat上
- 但是这个tomcat没有在本地保存该会话的数据,因此它会去相应的memcached中查找此次请求的会话数据并保存到本地
- (根据请求头中sessionid的后缀)
- 当这个tomcat处理完此次会话,它会将更新相应memcached节点存储的session信息
- 图示:
2.2 memcached的故障转移
- msm也实现了memcached的故障转移
- 当一个memcached节点不可用时,session信息就会被转移到其他memcached节点
- 与此同时,sessionid会被修改,一个新的JESESSIONID(响应头会有Set-Cookie:JESSIONID;XXXXXXXXXXXXX)会被发送到浏览器端
- 当使用粘性session(sticky session)时,要确保负载均衡不会给sessionid添加后缀
- SESSIONID的格式
- MSM知道Memcached节点列表,这些节点标识会存储在SESSIONID中
- SESSIONID值类似:602F7397FBE4D9932E59A9D0E52FE178-n1 【其中n1为Memcached节点标识】
3. MSM原理详解
3.1 MSM原理概述
- MSM利用Value(Tomcat阀)对Request进行跟踪
- Request请求来到时,从Memcached加载session
- Request请求结束时,将tomcat session更新到Memcached,以达到session共享之目的
- MSM支持黏性(sticky)和非黏性(non-sticky)模式
- 使用sticky模式时需要配置jvmRoute参数(在Engine标签中配置)
- 每台tomcat的jvmRoute参数都不能一样
3.2 Sticky和Non-Sticky模式
1)Sticky模式:
- 结构:
- tomcat session为主session
- memcached为备session
- Request请求到来时:
- 若tomcat jvmRoute没有发生变化,直接读取tomcat session
- 若tomcat jvmRoute发生变化,要从memcached加载备session到tomcat
- Request请求结束时,将tomcat session更新至memcached,以达到主备同步的目的
2)Non-Sticky模式:
- 结构:
- tomcat session为中转session
- memcached1为主session
- memcached2为备session
- Request请求到来时,从memcached2加载备session到tomcat
- 若只有一个memcached节点,或者memcached2出错时
- 容器中还是没有session,则从memcached1加载主session到tomcat
- Request请求结束时,将tomcat session更新至主memcached1和备memcached2
- 并清除tomcat session,以达到主备同步的目的
4. Tomcat分布式session共享(MSM)
4.1 说明
- 官网介绍说,使用kryo序列化tomcat的效率最高,采用kryo序列化
- 所需要安装的包:
4.2 No-Sticky模式
- 说明:
- 多个tomcat实例时,需要选择Non-Sticky模式,即sticky="false"
- 配置示例:
# 在<Context>中添加 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" # 配置memcached的节点信息,多个memcached节点中间需要使用空格或逗号隔开 memcachedNodes="n1:192.168.10.203:11211,n2:192.168.10.205:11211" lockingMode="auto" # 可选值,默认为none,只对non-sticky有效 sticky="false" # 使用Non-Sticky模式 sessionBackupAsync="false" # 可选值,默认为true,是否以异步的方式存储到memcached # 可选值,制定忽略那些请求的session操作,一般制定静态资源如css,js一类的 requestUriIgnorePattern=".*.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
4.3 Sticky模式
- 说明:
- 故障转移配置节点(failoverNodes),不能使用在Non-Stick模式,多个使用空格或逗号分隔开,配置某个节点为备份节点
- 当其他节点都不可用时才会存储到备份节点,适用于stick模式(一台tomcat,多台memcached)
- 配置示例:
# 在<Context>中添加: <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" #多个memcached之间用空格或逗号隔开都可以 memcachedNodes="n1:192.168.10.203:11211,n2:192.168.10.205:11211" sticky="true" failoverNodes="n2" requestUriIgnorePattern=".*.(png|gif|jpg|css|js|swf|flv)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" copyCollectionsForSerialization="true" />
4.4 测试的index.jsp页面
<%@ page language="java" %> <html> <head><title>TomcatB</title></head> <body> <h1><font color="red">TomcatB</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <% session.setAttribute("www.node1.com","www.node1.com"); %> <td><%= session.getId() %></td> </tr> <tr> <td>Created on</td> <td><%= session.getCreationTime() %></td> </tr> </table> <h1>10.0.0.204</h1> </body> </html>
4.5 在memcached中查看缓存的session信息
stats items STAT items:3:number 1 STAT items:3:age 24 STAT items:3:evicted 0 STAT items:3:evicted_nonzero 0 STAT items:3:evicted_time 0 STAT items:3:outofmemory 0 STAT items:3:tailrepairs 0 STAT items:3:reclaimed 0 STAT items:3:expired_unfetched 0 STAT items:3:evicted_unfetched 0 STAT items:5:number 1 STAT items:5:age 24 STAT items:5:evicted 0 STAT items:5:evicted_nonzero 0 STAT items:5:evicted_time 0 STAT items:5:outofmemory 0 STAT items:5:tailrepairs 0 STAT items:5:reclaimed 0 STAT items:5:expired_unfetched 0 STAT items:5:evicted_unfetched 0 END stats cachedump 3 0 ITEM bak:validity:C556BD8AF979FDAC3F311ACA1E3E2318-n2.TomcatB [20 b; 1576173776 s] END stats cachedump 5 0 ITEM bak:C556BD8AF979FDAC3F311ACA1E3E2318-n2.TomcatB [97 b; 1576175567 s] END
- 经过测试,发现session一样,测试成功