Session在分布式环境下存在的问题
由于HTTP协议是无状态的,在开发中我们可以将用户的信息存储在服务器的Session中,并生成与之对应的JSession,生成的JSession通过cookie返回给浏览器。该浏览器下次访问,cookie会自动携带上次请求存储的数据(JSession)到服务器中,服务器根据JSession找到对应的session,从而获取用户的信息。
该机制在单体应用中是没有问题的,但是如果在分布式环境下,会产生session共享问题,即session的数据在服务1中存在,但是在服务2中不存在。
这样会导致用户已经在服务1上登录过了,但请求服务2时找不到用户信息。
如何共享存储?
- Redis(基于内存的 K / V 数据库)此处选择 Redis,因为用户信息读取 / 是否登录的判断极其频繁 ,Redis 基于内存,读写性能很高,简单的数据单机 qps 5w - 10w
- MySQL
- 文件服务器 ceph
Session共享实现
-
安装Redis
官网:https://redis.io/windows 下载:
Redis 5.0.14 下载:
链接:https://pan.baidu.com/s/1XcsAIrdeesQAyQU2lE3cOg
提取码:vkoi
redis 管理工具 quick redis:https://quick123.net/
-
引入Redis,能够操作Redis
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.6.4</version> </dependency>
-
引入Spring-session和Redis的整合,使得自动将session存储到Redis中
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>2.6.3</version> </dependency>
-
修改 spring-session 存储配置
spring.session.store-type
spring: #session-timeout是session的持续时间,86400表示一天 session: timeout: 86400 store-type: redis #表示从redis读写session store-type默认为none表示存储在服务器内存中 #redis配置 redis: port: 6379 #端口 host: localhost database: 0 #库号
完成这些后,session的信息会默认存储在Redis中,就解决了Session共享的问题
拓展
Session不能跨不同域名共享
种 session 的时候注意范围,cookie.domain
比如两个域名:
aaa.yupi.com
bbb.yupi.com
如果要共享 cookie,可以种一个更高层的公共域名,比如 yupi.com
解决
在设置cookie时,指定domain为父域名(比如yupi.com)即可。
@Configuration
public class SessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainName("yupi.com");
return serializer;
}
}