[分布式]分布式会话session、spring-session
分布式会话
资料
前端鉴权的兄弟们:cookie、session、token、jwt、单点登录 - 掘金
分布式Session一致性的4种解决方案 - SegmentFault 思否
问题的提出
http是无状态的, 无法区分不同用户的请求(request); 为了解决这个问题, 传统的解决方法是cookie+session;
基于cookie+session登录校验流程:
单体服务的session一般存储在服务的内存里, 当服务集群化/分布式部署时, 不同服务上存储的session可能不同, 导致会话混乱, 出现"分布式会话"的问题;
如果服务端是集群,用户请求过来会走一次负载均衡,不一定打到哪台机器上。一旦用户后续接口请求到的机器和他登录请求的机器不一致,或者登录请求的机器宕机了,session就失效了
解决办法
- 从「存储」角度,把session集中存储, 比如存储到redis或数据库里; 或者不同机器间同步数据, 比如tomcat session同步; 集中存储到redis是最常见的方案;
- 从「分布」角度,让相同IP的请求在负载均衡时都打到同一台机器上。比如nginx配置ip_hash;
- 不使用session, 服务无状态化, 在微服务里比较流行;
spring session
资料
官方文档:
Spring Session
源码:
spring-projects/spring-session: Spring Session
大量示例:
Spring Session
上手
文档:
Spring Session - Spring Boot
示例代码:
https://gitee.com/qiaoxingxing/spring-security-learn/tree/master/spring-session-learn
依赖:
文档里少了lettuce-core的依赖, 报错:
No session repository could be auto-configured, check your configuration (session store type is 'redis')
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.4.RELEASE</version>
</dependency>
配置:
spring:
session:
store-type: redis
redis:
host: localhost
port: 6379
其他配置:
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds is used.
spring.session.redis.flush-mode=on_save # Sessions flush mode.
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
环境准备
# 启动redis
docker run -d --rm --name redis-test -p 6379:6379 redis
nginx配置:
upstream myapp1 {
# ip_hash;
server host.docker.internal:18080;
server host.docker.internal:18081;
}
server {
listen 28080;
location / {
proxy_pass http://myapp1;
}
}
启动nginx:
PWD=$(pwd -W)
docker container run -it -p 28080:28080 --rm --name mynginx \
--volume "${PWD}/conf/default-balance.conf":/etc/nginx/conf.d/default.conf \
nginx
启动两个实例:
mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=18080
mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=18081
测试
当spring.session.store-type: none
时, sessionid一直在变, 设置session无法使用;
设置为spring.session.store-type: redis
, 程序正常;