[分布式会话]springboot中实现session replication

分布式会话处理方式

分布式Session一般分为以下几种处理方式:

  • 粘性会话(sticky session):通过使每个用户每访问的服务端实例为同一个来确保session的正常使用
  • 会话拷贝(session replication):通过各个服务端实例之间的session复制,来确保每个服务端实例均具有session中的信息,以达到session的一致性
  • 会话第三方管理:通过redis等第三方的工具来存储session信息,使所有服务器实例均能访问到相同的session

其中session replication由于每个服务器实例都需要存储所有的session信息,并不适合规模较大的集群使用

会话拷贝(session replication)

tomcat只带了session replication的功能,只需要通过配置文件进行配置就可以使多个tomcat实例之间相互进行session拷贝,以下是来自tomcat官网文档的配置:

<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.MessageDispatchInterceptor"/>
  </Channel>

  <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
         filter=""/>
  <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.ClusterSessionListener"/>
</Cluster>

但是,如果使用了springboot中的内置tomcat,则需要通过java config的方式进行配置,而我在网络上并没有找到tomcat新版本的配置,于是通过官方文档及旧版配置进行了梳理,得出以下配置方法:

@Configuration
public class TomcatConfig {

    @Value("${tomcat.localClusterMemberPort}")
    private int localClusterMemberPort;

    @Value("${tomcat.clusterMembers}")
    private String clusterMembers;

    @Bean
    public TomcatServletWebServerFactory servletContainerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory() {
            @Override
            protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
                configureCluster(tomcat);
                return super.getTomcatWebServer(tomcat);
            }
        };

        factory.addContextCustomizers((TomcatContextCustomizer) context -> {
            context.setDistributable(true);
        });

        return factory;
    }

    private void configureCluster(Tomcat tomcat) {
        SimpleTcpCluster cluster = new SimpleTcpCluster();
        cluster.setChannelSendOptions(8);

        DeltaManager manager = new DeltaManager();
        manager.setExpireSessionsOnShutdown(false);
        manager.setNotifyListenersOnReplication(true);
        cluster.setManagerTemplate(manager);

        GroupChannel channel = new GroupChannel();

        NioReceiver receiver = new NioReceiver();
        receiver.setPort(localClusterMemberPort);
        channel.setChannelReceiver(receiver);

        ReplicationTransmitter sender = new ReplicationTransmitter();
        sender.setTransport(new PooledParallelSender());
        channel.setChannelSender(sender);

        channel.addInterceptor(new TcpPingInterceptor());
        //将消息调度到线程(线程池)以异步发送消息
        channel.addInterceptor(new TcpFailureDetector());
        channel.addInterceptor(new MessageDispatchInterceptor());

        StaticMembershipInterceptor membership = new StaticMembershipInterceptor();
        String[] memberSpecs = clusterMembers.split(",", -1);
        for (int i = 0; i < memberSpecs.length; i++) {
            String[] addrPart = memberSpecs[i].split(":");
            StaticMember member = new StaticMember();
            member.setHost(addrPart[0]);
            member.setPort(Integer.parseInt(addrPart[1]));
            member.setDomain("MyDomain");
            member.setUniqueId(String.valueOf(i).getBytes());
            membership.addStaticMember(member);
        }
        channel.addInterceptor(membership);

        cluster.setChannel(channel);

        cluster.addValve(new ReplicationValve());
        cluster.addValve(new JvmRouteBinderValve());
        cluster.addClusterListener(new ClusterSessionListener());

        tomcat.getEngine().setCluster(cluster);
    }

}

点击查看完整代码

扩展文章

[分布式会话]zuul通过负载均衡策略实现粘性会话(sticky session)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值