分布式系统中session一致性的说明及其解决方案(SpringSession)

本文探讨了在分布式系统中Session一致性的问题及解决方案,包括session同步、cookie存储、反向代理hash一致性与后端统一存储。深入分析了SpringSession在解决session一致性问题上的应用,包括其原理、优势及使用方法。
摘要由CSDN通过智能技术生成

一、谈一下HttpSession

1.HttpSession

其实Session作用域大家做后端开发的都清楚,用于会话级别的作用域,一般我们用其存储常用数据,这样就可以效率更高的拿到常用数据,而不需要再去占用一个数据库连接去查询数据库。

Session是存储在服务端的一个会话级别的对象,对应着客户端的一个会话,Session依赖于浏览器进程,当浏览器进程关闭,其Session也就失效了,因为服务器会根据浏览器的cookie中的JSESSIONID来确定当前客户端的session对象,一般的cookie不去做持久化设置,即内存级别的cookie,所以浏览器一关闭,cookie即被销毁了,对应的JSESSIONID自然无法继续保存。

2.前端的 web 存储技术也有session,application对象(了解)

浏览器的sessionStorage对应着我们后端的session,浏览器的localStorage对应着我们后端的application对象。作用其实都差不多。

3.会出现session一致性问题的场景

我们开发的后端服务都是不记录状态的API接口,也就是不会涉及到视图渲染、数据存储,后端服务接口只负责数据的响应。

自然这些事就需要前端服务来做。

在分布式系统中,各个服务都要为了解决单点故障来做服务器集群。

 这时候会当我们的前端服务做了集群之后,必须要做负载均衡,当用户请求过来后第一次被第一个前端服务处理,session数据存储到了第一台服务中,当用户再次访问项目时,被轮询到了第二台服务器,这时候第二台服务器就要重新为其创建一个session,导致用户的数据丢失,以至于功能根本无法正常实现,因为用户从第一台服务器登陆,只有第一台服务器的session中存在用户数据,这就出现了我们关注的数据一致性问题(session一致性问题)。

二、session一致性的几种解决方案

1.session同步(复制)                                    不使用

如果项目访问人数很少,并且是单体应用架构,可以考虑使用这种方案来解决,即只要有一个用户使用该系统,那么所有服务器上都要创建一个一模一样session对象。

  1. 优点
    1. web-server(Tomcat)原生支持,只需要修改配置文件
  2. 缺点
    1. session同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力
    2. 任意一台web-server保存的数据都是所有web-server的session总和,受到内存限制无法水平扩展更多的web-server。
    3. 大型分布式集群情况下,由于所有web-server都全量保存数据,所以此方案不可取。

2.session存储到cookie中                        傻子才用

  1. 优点
    1. 服务器不需存储session,用户保存自己的session信息到cookie中。节省服务端资源
  2. 缺点
    1. 都是缺点,这只是一种思路。
    2. 具体如下:
    3. 每次http请求,携带用户在cookie中的完整信息,浪费网络带宽
    4. session数据放在cookie中,cookie有长度限制4K,不能保存大量信息
    5. session数据放在cookie中,存在泄漏、篡改、窃取等安全隐患
    6. 这种方式不会使用。 

3.反向代理 hash一致性

原理:利用反向代理使得同一个用户的请求落在一台固定的服务器上,不要发生服务器切换即可,服务器之前内存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本来都是有有效期的。所以这两种反向代理的方式可以使用

4.后端统一存储 session数据

原理:将session存储在web-server后端的存储层,数据库或者缓存;但是由于session是频繁读取的数据而且有过期时间,所以我们一般存在Redis缓存中,而不是MySQL等db中

  1. 优点:
    1. 没有安全隐患
    2. 可以水平扩展,数据库/缓存水平切分即可
    3. web-server重启或者扩容都不会有session丢失
  2. 不足
    1. 增加了一次网络调用,并且需要修改应用代码;如将所有的getSession方法替换为从Redis查数据的方式

总结

  1. 保证session一致性的架构设计常见方法:
    1. session同步法多台web-server相互同步数据
    2. 客户端存储法一个用户只存储自己的session数据到cookie
    3. 反向代理hash一致性
      1. 保证一个用户的请求落在一台web-server
    4. 后端统一存储web-server重启和扩容,session也不会丢失
  2. 我们最终选择使用“后端统一存储这种方式”
  3. SpringSession是基于“后端统一存储”这种方式来管理session的;
    1. 只需配置一个Filter,SpringSession在Filter中使用装饰者模式和适配器模式包装原生request。
    2. SpringSession可以选择使用JDBC、Redis、Hazelcast、MongoDB等方式存储session
    3. SpringSession也可以定制请求头中带sessionid或者cookie中带sessionid
    4. 我们选择使用Redis存储session

三、SpringSession

1.SpringSession简介

SpringSession主要解决分布式情况下,session一致性的问题; 

session一致性:只要用户不重启浏览器,每次http短连接请求,理论上服务端都能定位到session,保持会话。

2.为什么要使用SpringSession

1、传统方式session问题

在传统单机web应用中,一般使用tomcat/jetty等web容器时,用户的session都是由容器管理。

浏览器使用cookie中记录sessionid,每次发送请求的时候会带上这个sessionid,web容器根据sessionid找到当时在服务存储信息时使用的那个Map,以此判断用户是否存在会话session。

注意:最大的问题是,session存储在web容器中,被单台服务器容器管理。

在分布式情况下,这会导致什么?

当然,如果我们一直玩单机版的应用,不用关心这个问题,但是随着业务逐渐增大,分布式应用和集群是趋势。

解决session不一致有很多方案,但多配置复杂或者有明显的缺点。有了SpringSession,所有的session由SpringSession创建维护,无需我们修改任何代码,就能在集群环境下使用原生的session方式编程,无侵入、简单配置和Spring应用无缝整合、对接各种session存储方案;

3.SpringSession的简单使用

1.引入依赖

<!-- 引入springboot&redis整合场景 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入springboot&springsession整合场景 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>

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获取到的都是一样的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值