SpringBoot使用Redis实现Tomcat集群的session同步操作

概述


在tomcat等web容器中,session是保存在本机内存中。如果我们对tomcat做集群,不可避免要涉及到session同步的问题,必须保证同一个集群中的tomcat的session是共享的。

为了保证tomcat集群正常工作 ,通常采用以下方法:

  • 在tomcat前端配置nginx中,在server.xml中配置ip_hash负载均衡算法来保证同一个ip的访客固定访问同一个后端服务器,避免多个tomcat需要session同步问题,缺点就是如果服务器宕机了,则所有在该服务器上的用户状态就都会丢失

  • 通过tomcat自带的cluster方式,多个tomcat之间实时共享session信息,但是此方法随着tomcat数量和请求量增加性能会下降的比较厉害

  • 利用filter方法

  • 利用terracotta服务器共享session

  • 利用redis、memcached等中间件存储session

SpringBoot中使用Redis实现session共享


引入依赖:

 <dependency>
             <groupId>org.springframework.session</groupId>
             <artifactId>spring-session-data-redis</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>

application.yaml中的配置


 spring:
   session:
 # session的存储方式的类型配置
     store-type: redis
 # session 存活时间
     timeout: 300
 #配置Tomcat多端口号
     additionalPorts: 9090,9091

TomcatConfig配置类


 import org.apache.catalina.connector.Connector;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 ​
 import java.util.ArrayList;
 import java.util.List;
 ​
 /**
  * @Description: 增加端口监听
  * @Class: TomcatConfig
  * @Author: Yiang37
  * @Date: 2021/9/3 15:56
  * @Version: 1.0
  */
 @Configuration
 public class TomcatConfig {
 ​
     @Value("${server.additionalPorts}")
     private String additionalPorts;
 ​
     @Bean
     public TomcatServletWebServerFactory servletContainer() {
         TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
         Connector[] additionalConnectors = this.additionalConnector();
         if (additionalConnectors != null && additionalConnectors.length > 0) {
             tomcat.addAdditionalTomcatConnectors(additionalConnectors);
         }
         return tomcat;
     }
 ​
     private Connector[] additionalConnector() {
         if (StringUtils.isBlank(this.additionalPorts)) {
             return null;
         }
         // 端口按,分割
         String[] ports = this.additionalPorts.split(",");
         List<Connector> result = new ArrayList<>();
         for (String port : ports) {
             Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
             connector.setScheme("http");
             connector.setPort(Integer.parseInt(port));
             result.add(connector);
         }
         return result.toArray(new Connector[] {});
     }
 ​
 }

启动类上添加注解

@import({TomcatConfig.class})

测试类RedisHandler


此类中有三个方法:

login()模拟登录,在session中存储一个值

 @RequestMapping("/login")
     publicMap<String,Object>login(HttpServletRequestrequest){
 ​
         HttpSessionsession=request.getSession();
         //设置session中的值
         session.setAttribute("username","sq"+System.currentTimeMillis());
         Map<String, Object>sqMap=newHashMap<>();
         Enumeration<String>attributeNames=request.getSession().getAttributeNames();
         while (attributeNames.hasMoreElements()){
             Stringname=attributeNames.nextElement();
             sqMap.put(name,session.getAttribute(name));
         }
         sqMap.put("sessionId",session.getId());
         returnsqMap;
     }

getSession():从session中获取值

 @RequestMapping("get-session")
 publicObjectgetSession(HttpServletRequestrequest) {
     HttpSessionhttpSession=request.getSession();
     Map<String,Object>rtnMap=newHashMap<>();
     Enumeration<String>attributeNames=request.getSession().getAttributeNames();
     while(attributeNames.hasMoreElements()){
         Stringname=attributeNames.nextElement();
         rtnMap.put(name, httpSession.getAttribute(name));
     }
     intcount;
     try {
         count=Integer.parseInt(String.valueOf(httpSession.getAttribute("count")));
         count++;
     }catch (NumberFormatExceptione){
         count=1;
     }
     httpSession.setAttribute("count",count+"");
     rtnMap.put("sessionId", httpSession.getId());
     returnrtnMap;
 }

invalidate(): 使的sesion值失效

 @RequestMapping("invalidate")
 publicintinvalidate(HttpServletRequestrequest) {
      HttpSessionhttpSession=request.getSession();
      httpSession.invalidate();
      return1;
  }

测试


启动RedisApplication应用,再启动项目

登录:localhost:8080/login

获取session

从另一个服务器端口号访问

服务重启后sessionid不变,说明redis保存session生效,成功!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值