引言
本文代码已提交至Github(版本号:
3b2359205b2d49f9eae313d8cca119082dd7bc99
),有兴趣的同学可以下载来看看:https://github.com/ylw-github/taodong-shop
本文主要解决分布式Session的问题。
本文目录结构:
1. 分布式Session的问题
1.首先在「淘东电商」项目里复制一个portal-web
,并修改端口号为8081,模拟门户集群,如下图:
2.项目新增controller,作为验证:
@RestController public class TestSessionController { @Value("${server.port}") private Integer projectPort;// 项目端口 @RequestMapping("/createSession") public String createSession(HttpSession session, String name) { session.setAttribute("name", name); return "当前项目端口:" + projectPort + " 当前sessionId :" + session.getId() + "在Session中存入成功!"; } @RequestMapping("/getSession") public String getSession(HttpSession session) { return "当前项目端口:" + projectPort + " 当前sessionId :" + session.getId() + " 获取的姓名:" + session.getAttribute("name"); } }
3.Nginx负载均衡配置:
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream backServer{ server 192.168.18.166:8080; server 192.168.18.166:8081; } server { listen 8099; server_name 192.168.166.137; location / { proxy_pass http://backServer; index index.html index.htm; } } }
4.浏览器请求获取session,浏览器请求http://192.168.162.137:8099/getSession:
请求一次 | 请求二次 |
可以看到两次Session的id不一致,并不是我们想要的。那该如何解决呢?下面来讲解决方案。
2. 解决方案
解决方案有如下几种:
- 使用cookie来完成(缺点:不安全,操作不可靠)
- 使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(缺点:不支持负载均衡)
- 利用数据库同步session(缺点:效率不高)
- 使用tomcat内置的session同步(缺点:同步可能会产生延迟)
- 使用token代替session(已经有很好的解决方案了,使用spring-session)
- 我们使用spring-session以及集成好的解决方案,存放在redis中(推荐)。
3. spring-session
step1:首先引入spring-session的maven依赖:
<!--spring session 与redis应用基本环境配置,需要开启redis后才可以使用,不然启动Spring boot会报错 --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
step2:配饰Redis:
spring: redis: host: 192.168.162.136 port: 6379 jedis: pool: max-idle: 100 min-idle: 1 max-active: 1000 max-wait: -1
step3: 启动类声明允许使用Session共享:
//maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒) @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class AppPortalWeb { public static void main(String[] args) { SpringApplication.run(AppPortalWeb.class, args); } }
4. 测试
启动项目:
首先浏览器创建session并设置内容到session:http://192.168.162.137:8099/createSession?name=‘ylw’
浏览器请求:http://192.168.162.137:8099/getSession,可以看到两次的sessionid均为:f8b9a9ab-d285-4b04-8d98-66715cbdc132
请求8080 | 请求8081 |
打开Medis,可以看到redis已经保存了相关的redis的值:
总结
本文主要讲解分布式环境下,使用spring-session解决session共享的问题。