Http协议本身是无状态的,为了保存会话信息,浏览器Cookie通过SessionID标识会话请求,服务器以SessionID为key来存储会话信息。在单实例应用中,可以考虑应用进程自身存储,随着应用体量的增长,需要横向扩容,多实例Session共享问题随之而来。
下面假设我们使用Nginx来实现负载均衡横向扩节点:

在这样的架构中,会出现无法获取到Session信息,不知道是哪个用户的请求。例如客户端发起一个请求,这个请求到了Nginx之后,会被Nginx转发到 Tomcat A上,然后在Tomcat A上的Session存储数据。后面又来一个请求,这个请求被Nginx转发到Tomcat B上,此时再去获取Session会发现没有数据。对于这样的问题有一个主流的解决办法,就是实现共享Session,把Session存储到Reids里面。如下:

这样无论存储还是读取Session的操作,都是去操作Redis中存储Session信息而不是自身内存中的Session,其他Tomcat也是如此,这样就实现了Session 共享。
一、添加依赖
除了Redis依赖之外,这里还要提供spring-session-data-redis依赖,SpringSession可以做到透明化地替换掉应用的Session容器。
1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 <exclusions> 5 <exclusion> 6 <groupId>io.lettuce</groupId> 7 <artifactId>lettuce-core</artifactId> 8 </exclusion> 9 </exclusions> 10</dependency> 11<dependency> 12 <groupId>redis.clients</groupId> 13 <artifactId>jedis</artifactId> 14</dependency> 15<dependency> 16 <groupId>org.springframework.session</groupId> 17 <artifactId>spring-session-data-redis</artifactId> 18</dependency>
二、Application.properties中配置Redis连接信息:
1#### redis 配置 #### 2# 基本连接信息配置 3spring.redis.database = 0 4spring.redis.host = 127.0.0.1 5spring.redis.port = 6379 6spring.redis.password = 123456 7# 连接池信息配置 8spring.redis.jedis.pool.max-active = 8 9spring.redis.jedis.pool.max-idle = 8 10spring.redis.jedis.pool.max-wait = -1ms 11spring.redis.jedis.pool.min-idle = 0 12spring.redis.timeout = 0
三、编写测试Controller
1import org.springframework.beans.factory.annotation.Value; 2import org.springframework.web.bind.annotation.GetMapping; 3import org.springframework.web.bind.annotation.PathVariable; 4import org.springframework.web.bind.annotation.RestController; 5 6import javax.servlet.http.HttpSession; 7 8@RestController 9public class SessionController { 10 11 @Value("${server.port}") 12 String port; 13 14 @GetMapping("/save/{name}") 15 public String saveName(@PathVariable("name") String name, HttpSession session) { 16 session.setAttribute("name", name); 17 return port; 18 } 19 20 @GetMapping("/get") 21 public String getName(HttpSession session) { 22 return port + ":" + session.getAttribute("name").toString(); 23 } 24 25}
四、运行项目
(1)使用maven打包运行,然后传入不同端口参数启动。
1mvn clean package 2 3nohup java -jar test-0.0.1-SNAPSHOT.jar --server.port=8080 & 4nohup java -jar test-0.0.1-SNAPSHOT.jar --server.port=8081 &
nohup 表示不挂断程序运行,即当终端窗口关闭后,程序依然在后台运行,最后的 & 表示让程序在后台运行。
(2)使用idea编译器启动多个项目,设置不同端口参数。
如果想使用该方案,可以查看这篇文章:IDEA 启动多个SpringBoot项目不同端口
五、验证结果
1.我们先请求8081端口的save接口,存储一个session数据。

2.请求8081端口get接口,获取session数据。

3.请求8082端口的get接口,获取session数据。
