一、分布式Session
单体项目中我们使用Session和Cookie保存用户信息,而在分布式系统中单独使用Session和Cookie无法已无法满足要求。一、Session不能跨系统保存,二、Cookie的跨域问题
1.1 分布式Session解决方案
① session 复制
优点:web-server
(Tomcat
)原生支持,只需要修改配置文件
缺点:
session
同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力- 任意一台
web-server
保存的数据都是所有web-server
的session
总和,受到内存限制无法水平扩展更多的web-server
- 大型分布式集群情况下,由于所有
web-server
都全量保存数据,所以此方案不可取。
② session 存储在客户端
优点:服务器不需存储session
,用户保存自己的session
信息到cookie
中,节省服务端资源
缺点:
- 每次http请求,携带用户在cookie中的完整信息,浪费网络带宽
- session数据放在cookie中,cookie有长度限制4K,不能保存大量信息
- session数据放在cookie中,存在泄漏、篡改、窃取等安全隐患
session 存储在客户端这种方式不可取,不能使用。
③ hash 一致性
优点:
- 只需要改
nginx
配置,不需要修改应用代码 - 负载均衡,只要
hash
属性的值分布是均匀的,多台web-server
的负载是均衡的 - 可以支持
web-server
水平扩展(session
同步法是不行的,受内存限制)
缺点:
session
还是存在web-server
中的,所以web-server
重启可能导致部分session
丢失,影响业务,如部分用户需要重新登录- 如果
web-server
水平扩展,rehash
后session
重新分布,也会有一部分用户路由不到正确的session
④ 统一存储
优点:
- 没有安全隐患
- 可以水平扩展,数据库/缓存水平切分即可
web-server
重启或者扩容都不会有session
丢失
缺点:增加了一次网络调用,并且需要修改应用代码;如将所有的getSession
方法替换为从Redis
查数据的方式,redis
获取数据比内存慢很多。
2.2 SpringSession
通常我们会选择统一存储的方案,其缺点可以使用SpringSession
进行解决。
① 引入依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
② 配置
spring.session.store-type=redis
server.servlet.session.timeout=30m
spring.redis.host=192.168.1.100
③ 主启动类添加注解@EnableRedisHttpSession
④ 存在的问题
现在存在的问题是子域名下会保存cookie
,但是在父域名中却没有,我们希望只要在子域名下的cookie
,父域名也能感知到。
- 由于默认使用
jdk
进行序列化,通过导入RedisSerializer
修改为json
序列化 - 并且通过修改
CookieSerializer
扩大session
的作用域至**.test.com
@Configuration
public class TestSessionConfig {
@Bean // redis的json序列化
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
@Bean // cookie
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("GULISESSIONID"); // cookie的键
serializer.setDomainName("test.com"); // 扩大session作用域,也就是cookie的有效域
return serializer;
}
}
使用SpringSession
其实还存在Cookie
的跨域问题,无法跨级,只能实现二级域名的跨域,多系统使用单点登录可以解决这个问题。
二、单点登录
分布式系统登录解决方案单点登录流程如下:
详细UML
图:
拦截器代码: