SpringBoot入门系列(二十八)使用Redis实现分布式Session共享
前面介绍了Spring Boot如何使用Redis缓存。接下来从项目实战出发,介绍使用Redis实现Session共享。
在分布式或微服务系统中,会出现这样一个问题:用户在服务器A上登录以后,假如后续的业务操作被负载均衡服务转发到服务器B上面,服务器B上没有这个用户的Session状态,就会强制让用户重新登录,导致业务无法顺利完成。因此,这就需要将Session进行共享,保证每个系统都能获取用户的Session状态。
1、分布式Session共享解决方案
目前主流的分布式Session共享主要有以下几种解决方案:
客户端存储,使用Cookie来完成,其缺点是不安全、不可靠。
Session绑定,使用Nginx中的IP绑定策略,同一个IP指定访问同一个机器,其缺点是容易造成单点故障。如果某一台服务器宕机,那么该台服务器上的Session信息将会丢失。
Session同步,使用tomcat内置的Session同步,其缺点是同步可能会产生延迟。
Session共享,将Session存储在Redis等缓存中间件中。
以上解决方案各有优缺点,其中,比较流行的是使用Redis等缓存中间件的Session共享解决方案。将所有的Session会话信息存入Redis缓存中,然后Web应用从Redis中取出Session信息实现所有应用的Session共享。具体示意图如图11-3所示。
从上图可以看出,所有的服务都将Session的信息存储到Redis中,无论是对Session的注销、更新都会同步到Redis中,从而达到Session共享的目的。
2 、使用Redis实现Session共享
前面介绍了使用Redis实现Session共享的解决方案。下面通过示例演示使用Redis实现Session信息存储,并实现多系统的Session信息共享。
1.引入依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- 引入 redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
上面的示例中,引入除了Redis组件外,还需要引入spring-session-data-redis依赖。通过此组件实现session信息的管理。
2.添加Session配置类
创建SessionConfig配置类,配置打开Session,示例代码如下:
public class SessionConfig {
}
上面的示例,配置Session的缓存时间。maxInactiveIntervalInSeconds:设置Session失效时间,使用Redis共享Session之后,原Spring Boot的server.session.timeout属性不再生效。
经过上面的配置后,Session调用就会自动去Redis上存取。另外,想要达到Session共享的目的,只需要在其他的系统上做同样的配置即可。
3.测试验证
首先,增加Session的测试方法。
String uid(HttpSession session) {
UUID uid = (UUID) session.getAttribute("uid");
if (uid == null) {
uid = UUID.randomUUID();
}
session.setAttribute("uid", uid);
return session.getId();
}
然后,启动项目,运行一个程序实例,启动端口号为8080,在浏览器中输入地址:“http://localhost:8080/uid”,页面返回会话的sessionId:
我们可以登录Redis客户端,查看session是否已经保存到Redis,输入“keys '*sessions*'”查看所有的Session信息:
从上面的输出可以看到,sessionId是7433a35d-a086-4b7d-bb64-37cf8b4e18f7,与页面返回的sessionId一致。说明Redis中缓存的SessionId和实际使用的Session一致,Session已经在Redis中进行有效的管理。
最后,我们模拟分布式系统,再启动一个程序实例,启动端口号为8081,在浏览器中输入“http://localhost:8081/uid”,页面返回会话的SessionId为:
从输出结果可以看到,程序实例1和程序实例2获取到的是同一个Session,这说明两个程序实现了Session共享。