分布式session的解决方案
1、采用分布式部署后会产生什么Session问题
如果通过Nginx的方式配置了负载均衡(轮询的方式)页面请求到不同后端服务器后都会产生创建新的Session,导致两个不服务器有不同的Session。
2、分布式session问题产生的原因
Session的底层是基于Cookie的,我们每次服务端创建了一个Session 都会向Cookie里面写入一个key是JSESSONID,value
是SessionId 的键值对。当我们关闭浏览器的时候Cookie 就消失了。在打开页面请求后端服务时请求里面没有Cookie信息。如果通过Nginx的方式配置了负载均衡(轮询的方式),
请求到两个服务端后,内存中根据SessionId找不到原来创建的Session,所以就新创建一个Session。这就是分布式Session产生的原因。
3、分布式session问题的解决办法
3.1 使用 Redis
使用docker Redis 服务端
2、创建存放redis文件夹用于存放redis mkdir /Users/gaoheqiang/redis-data3、使用redis镜像运行redis容器 docker run -p 6379:6379 -v /usr/data/redis/data:/data --restart=always --name redis -d redis:latest redis-server --appendonly yes --requirepass "lcl123456" 命令说明: -p:宿主机端口与容器端口映射 -v:挂载,将容器中的redis持久化数据挂载到宿主机,避免容器重启导致的数据丢失。 --restart=always:无论什么情况挂壁,总是重启 --name:容器名称 -d:使用指定的镜像(redis的4.0.8版本的镜像)在后台运行容器 --appendonly yes:redis运行时开启持久化 --requirepass "lcl123456":设置redis登陆密码
创建session 的配置文件
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class SessionConfig { @Value("${redis.hostname}") String hostName; @Value("${redis.port}") int port; @Value("${spring.redis.password}") String password; @Bean public JedisConnectionFactory jedisConnectionFactory(){ JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); connectionFactory.setPort(port); connectionFactory.setHostName(hostName); connectionFactory.setPassword(password); return connectionFactory; } @Bean public StringRedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { return new StringRedisTemplate(redisConnectionFactory); } }
初始化Session 配置
/** * 初始化Session配置 */ public class SessionInitializer extends AbstractHttpSessionApplicationInitializer { public SessionInitializer() { super(SessionInitializer.class); } }
Spring-Sesion实现的原理
当Web服务器接收到请求后,请求会进入对应的Filter进行过滤,将原本需要由Web服务器创建会话的过程转交给Spring-Session进行创建。
Spring-Session会将原本应该保存在Web服务器内存的Session存放到Redis中。然后Web服务器之间通过连接Redis来共享数据,达到Sesson共享的目的。
验证结果
通过nginx 访问后端的服务,第一次是访问时Session 是 新建的,第二次是用原来的,这样验证使用Redis 解决了分布式session的问题。