一般HttpSession是通过Servlet容器创建并进行管理的, 创建成功之后都是保存在内存中。如果是项目是搭建的集群, 则来自于同一用户的http请求有可能备份发到不同的实例中, 如何保证各个实例之间的Session同步共享, SpringBoot提供了自动化的Session共享配置, 主要是结合Redis解决这个问题。使用Redis解决Session共享问题的原理非常简单, 就是把原本存储在不同服务器上的Session拿出来放在一个独立的服务器上,如图:
当一个请求到达ngnix服务器后, 首先尽心请求分发, 假设请求被real server1 处理了, real server在处理请求时, 无论是存储还是读取Session, 都去操作Session服务器, 而不是操作本地内存, 这样就实现了Session共享;
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<artifactId>io.lettuce</artifactId>
<groupId>lettuce-core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
配置文件:
spring.redis.database=0
spring.redis.host=192.168.0.160
spring.redis.port=6379
spring.redis.password=123456
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
- 创建Controller测试:
/** * session共享 */ @RestController public class RedisController { @Value("${server.port}") String port; @PostMapping("/save") public String saveName(String name, HttpSession session){ session.setAttribute("name",name); return port; } @GetMapping("/getname") public String getName(HttpSession session){ return port+":"+session.getAttribute("name").toString(); } }
/save接口向Session中存储数据, get接口获取Session中数据, 根据port来看, 具体是哪个服务在提供服务;
- 配置Nginx负载均衡:
upstream batac.com{
server 192.168.0.160:7020 weight=1;
server 192.168.0.160:7021 weight=1;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
location ~/group1/ {
ngx_fastdfs_module;
}
#access_log logs/host.access.log main;
location / {
proxy_pass http://batac.com;
proxy_redirect default;
}
}
- 请求分发: