其实Session作用域大家做后端开发的都清楚,用于会话级别的作用域,一般我们用其存储常用数据,这样就可以效率更高的拿到常用数据,而不需要再去占用一个数据库连接去查询数据库。
Session是存储在服务端的一个会话级别的对象,对应着客户端的一个会话,Session依赖于浏览器进程,当浏览器进程关闭,其Session也就失效了,因为服务器会根据浏览器的cookie中的JSESSIONID来确定当前客户端的session对象,一般的cookie不去做持久化设置,即内存级别的cookie,所以浏览器一关闭,cookie即被销毁了,对应的JSESSIONID自然无法继续保存。
浏览器的sessionStorage对应着我们后端的session,浏览器的localStorage对应着我们后端的application对象。作用其实都差不多。
我们开发的后端服务都是不记录状态的API接口,也就是不会涉及到视图渲染、数据存储,后端服务接口只负责数据的响应。
自然这些事就需要前端服务来做。
在分布式系统中,各个服务都要为了解决单点故障来做服务器集群。
这时候会当我们的前端服务做了集群之后,必须要做负载均衡,当用户请求过来后第一次被第一个前端服务处理,session数据存储到了第一台服务中,当用户再次访问项目时,被轮询到了第二台服务器,这时候第二台服务器就要重新为其创建一个session,导致用户的数据丢失,以至于功能根本无法正常实现,因为用户从第一台服务器登陆,只有第一台服务器的session中存在用户数据,这就出现了我们关注的数据一致性问题(session一致性问题)。
如果项目访问人数很少,并且是单体应用架构,可以考虑使用这种方案来解决,即只要有一个用户使用该系统,那么所有服务器上都要创建一个一模一样session对象。
原理:利用反向代理使得同一个用户的请求落在一台固定的服务器上,不要发生服务器切换即可,服务器之前内存session中的数据还是在的;可以有两种实现;
1.四层代理 根据ip做hash一致性
原理:反向代理层使用用户ip来做hash,以保证同一个ip的请求落在同一个web-server(tomcat)上
2.七层代理 根据http协议任意业务字段自定义hash
原理:反向代理使用http协议中的某些业务属性来做hash,例如sid,city_id,user_id等,能够更加灵活的实施hash策略,以保证同一个浏览器用户的请求落在同一个web-server上
OSI七层协议
优点:
只需要改nginx配置,不需要修改应用代码
负载均衡,只要hash属性的值分布是均匀的,多台web-server的负载是均衡的
可以支持web-server水平扩展(session同步法是不行的,受内存限制)
缺点
session还是存在web-server中的,所以web-server重启可能导致部分session丢失,影响业务,如部分用户需要重新登录
如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session
但是以上缺点问题也不是很大,因为session本来都是有有效期的。所以这两种反向代理的方式可以使用
原理:将session存储在web-server后端的存储层,数据库或者缓存;但是由于session是频繁读取的数据而且有过期时间,所以我们一般存在Redis缓存中,而不是MySQL等db中
SpringSession主要解决分布式情况下,session一致性的问题;
session一致性:只要用户不重启浏览器,每次http短连接请求,理论上服务端都能定位到session,保持会话。
1、传统方式session问题
在传统单机web应用中,一般使用tomcat/jetty等web容器时,用户的session都是由容器管理。
浏览器使用cookie中记录sessionid,每次发送请求的时候会带上这个sessionid,web容器根据sessionid找到当时在服务存储信息时使用的那个Map,以此判断用户是否存在会话session。
注意:最大的问题是,session存储在web容器中,被单台服务器容器管理。
在分布式情况下,这会导致什么?
当然,如果我们一直玩单机版的应用,不用关心这个问题,但是随着业务逐渐增大,分布式应用和集群是趋势。
解决session不一致有很多方案,但多配置复杂或者有明显的缺点。有了SpringSession,所有的session由SpringSession创建维护,无需我们修改任何代码,就能在集群环境下使用原生的session方式编程,无侵入、简单配置和Spring应用无缝整合、对接各种session存储方案;
1.引入依赖
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session-data-redis
2.简单配置redis和spring-session
# redis配置 spring.redis.host=39.98.76.67 #spring.redis.pool.max-active=100 spring.redis.jedis.pool.max-idle=100 # springsession配置 spring.session.store-type=redis
# session过期时间 spring.session.timeout=1800 |
3.controller
@RestController
@SpringBootApplication
public class SpringSession01Application {
public static void main(String[] args) {
SpringApplication.run(SpringSession01Application.class, args);
}
@GetMapping("/set")
public String setSession(HttpSession session){
session.setAttribute("msg", "Hello");
return "ok";
}
@GetMapping("/get")
public String getSession(HttpSession session){
return (String) session.getAttribute("msg");
}
}
我们可以看到,redis中保存了数据,而且如果我们设置多台服务器,访问get获取到的都是一样的 |