前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >tomcat cluster session同步时保存map数据遇到的问题

tomcat cluster session同步时保存map数据遇到的问题

作者头像
编程随笔
发布2019-09-11 15:44:37
8210
发布2019-09-11 15:44:37
举报
文章被收录于专栏:后端开发随笔后端开发随笔

Tomcat Cluster官网:https://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html(tomcat7.0)

场景:

tomcat1 tomcat2 | | --------|--------- nginx

tomcat版本:7.0.59

1.后端应用为2台tomcat容器,并且配置了Tomcat Cluster实现session同步; 2.nginx为前端web服务器,负责反向代理和负载均衡(简单轮训),配置如下:

代码语言:javascript
复制
upstream tomcat {
  server 192.168.70.130:8080;
  server 192.168.70.131:8080;
}

3.在应用代码中将一个map对象存放在session中,即:

代码语言:javascript
复制
Map<String, Object> map = new HashMap<String, Object>();
map.put("email", "12345");
req.getSession().setAttribute(Constants.KEY_SESSION_MAP, map);

问题: t1: 请求1经过nginx访问到tomcat1,此时将session中保存的map对象取出来,同时更改map对象保存的<key:value>值:

代码语言:javascript
复制
Map<String, Object> map = (Map<String, Object>) req.getSession().getAttribute(Constants.KEY_SESSION_MAP);
map.put("email", "67890");

t2: 请求2经过nginx访问到tomcat2,取出session中保存的map对象,并取得其中的<key:value>值:

代码语言:javascript
复制
Map<String, Object> map = (Map<String, Object>) req.getSession().getAttribute(Constants.KEY_SESSION_MAP);
map.get("email");

这时发现,在tomcat2中取得的map对象<key:value>与在tomcat1中修改后存放的<key:value>不一致! 具体来说,在tomcat1中map对象修改后存放的<key:value>值为:<"email":"67890">,但是在tomcat2中map对象取出来的<key:value>依然为之前的值:<"email":"12345">。 看起来,tomcat的集群session同步失效了?!

原因:

代码语言:javascript
复制
Data is only replicated if the session has changed (by calling setAttribute or removeAttribute on the session).

即:只有当明确调用session.setAttribute()或者session.removeAttribute()时才会同步session数据。 详见:https://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html Cluster Information Tomcat集群配置:

代码语言:javascript
复制
<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="auto"
            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.MessageDispatch15Interceptor"/>
  </Channel>
  <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
        filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
  <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.JvmRouteSessionIDBinderListener" />
  <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>

如上所示,Tomcat集群使用org.apache.catalina.ha.session.DeltaManager管理session同步,追踪源码:

代码语言:javascript
复制
@Override
public Session createEmptySession() {
return getNewDeltaSession() ;
}
/**
* Get new session class to be used in the doLoad() method.
*/
protected DeltaSession getNewDeltaSession() {
return new DeltaSession(this);
}

显然,DeltaManager创建的Session实例为org.apache.catalina.ha.session.DeltaSession对象实例。

DeltaSession保存数据时序图:

如上图所示,org.apache.catalina.ha.session.DeltaSession在保存数据时将发送集群消息,以实现session数据同步。

解决办法: 当session中保存的数据发生改变时,需要重新调用session.setAttribute(),这样才会在集群中同步最新的session数据,即:

代码语言:javascript
复制
// 修改session中map对象保存的值
Map<String, Object> map = (Map<String, Object>) req.getSession().getAttribute(Constants.KEY_SESSION_MAP);
map.put("email", "67890");
req.getSession().setAttribute(Constants.KEY_SESSION_MAP, map); // session保存的值发生改变时,必须重新调用session.setAttribute()触发session数据同步

总结: 在使用Tomcat Cluster进行session同步时,保存在session中的数据如果发生了变化,则必须重新调用session.setAttribute()进行保存。这样才能触发Tomcat发送集群消息,将最新修改的session数据同步到其他节点上。其实不难理解,Tomcat Cluster之所以采用这样的数据同步机制,就是希望当session发生变化(通过保存或删除数据)时才进行同步,减少不必要的集群同步消息。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-05-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档