转载

快速实现 Tomcat 集群 Session 共享

在应对巨大的用户流量的互联网场景中, 搭建 Tomcat 集群是缓解 Web 服务器负载的解决方式中必不可少的,而随之带来的会话信息即 Session 不同步的问题也暴露出来: 用户刚登录后,再次操作却提示需要重新登录,严重影响着用户体验. 本文主要研究如何使用 Spring Session 框架来解决 Tomcat 集群会话共享问题.若有补充,欢迎斧正.

正文

环境准备

  • 3个 Tomcat 实例
  • Redis

项目结构

项目比较简单,除了启动类之外,就只有一个控制器类.

快速实现 Tomcat 集群 Session 共享

控制器实现

UserController 主要有两个请求方法, 一个接受用户登录,另一个获取登录信息的;当调用 login 接口后将请求数据存在当前的 Session 中,然后在 Session 有效的期间内调用 getUserInfo 接口都能获取到对应登录时的数据.

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public String login(HttpSession session, HttpServletRequest request) {
        String id = request.getParameter("id");
        String name = request.getParameter("name");
        HashMap<Object, Object> userInfo = new HashMap<>(16);
        userInfo.put("id", id);
        userInfo.put("name", name);
        session.setAttribute("USER_INFO", userInfo);
        return userInfo + "  成功存储到会话中";
    }

    @RequestMapping("/getUserInfo")
    public String getUserInfo(HttpSession session, HttpServletRequest request) {
        Object user_info = session.getAttribute("USER_INFO");
        if (user_info == null) {
            return "请先登录,再读取会话数据";
        }
        return "从会话中读取数据 " + user_info;
    }
}
复制代码

现在我们将3个 Tomcat 实例搭建成集群,然后都运转这个项目; 如果我们针对一个 Tomcat 实例发送登录请求,然后再次发送获取用户信息请求,此时这个 Tomcat 是能够正确返回之前登录后存储的信息;而当我们在另一个 Tomcat 实例尝试获取用户信息时,则会返回 "请先登录,再读取会话数据";这说明这两个 Tomcat 实例的会话信息是独立存在的.

使用 Spring Session

现在想要让这些 Tomcat 间能够对会话信息共享,只要登录一次,就可以在其他集群实例上访问数据,就可以使用 Spring Session 框架实现,它能在对程序无任何侵入的情况 实现 Session 的共享. 首先我们要做 POM 文件引入 Spring Session 相关的库

<dependency>
		<groupId>org.springframework.session</groupId>
		<artifactId>spring-session-data-redis</artifactId>
	</dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
复制代码

从依赖的库可以看到 Spring Session 利用内存数据库 Redis 来存储会话信息,以此达到集群间会话的共享.

引入后依赖库之后,我们就需要在 application.properties 文件上进行 Session 的配置.

server.servlet.session.timeout=3600 //1
spring.session.redis.flush-mode=IMMEDIATE //2 
spring.session.redis.namespace=spring:session //3

// 4
spring.redis.host=127.0.0.1
spring.redis.password=
spring.redis.port=6380
复制代码

先简单对文件新增的配置进行简单的说明:

SessionRepository.save(org.springframework.session.Session)

然后在将项目打包到各个 Tomcat 之后再次调用登录请求,然后在 Redis 中查询下当前所有 KEYS

快速实现 Tomcat 集群 Session 共享

从图里就可以看出缓存中对 Session 数据的命名就是以前配置文件中的命名空间来的,我们取一下里面的 KEY 查看它的内容,里面就有我们所存的用户信息

快速实现 Tomcat 集群 Session 共享

然后我们再对另个 Tomcat 请求获取用户信息,就可以发现返回结果不再是之前的"请先登录,再读取会话数据",而能正常返回在之前一台 Tomcat 实例上登录的会话数据信息.这也说明了 Tomcat 集群间的会话共享实现了, 是不是很简单呢?

参考

  • docs.spring.io/spring-sess…
  • docs.spring.io/spring-sess…
原文  https://juejin.im/post/5c4e4591e51d453aa364e27e
正文到此结束
Loading...