我们知道,对于一个单机系统来说,用户登陆成功后,一般情况下服务端会通过在httpRequest的session中存入登陆后的信息,客户端二次请求的时候,通过cookie对于的sessionId来获取验证用户的登陆状态。但是当业务量过大,需要拓展到多台机器来缓解单机瓶颈时,这种情况就不适用了。
如下所示,客户端第一次登陆请求进来,被nginx负载到服务器1,验证登陆通过后,登陆信息存放在服务器1上,当客户端第二次请求的时候,因此被分发到服务器2,而服务器2因为找不到服务器1的session信息,结果导致客户端又需要重新登陆一次。
TIM图片20191117010625
为了解决这种情况,我们引入分布式会话,通过redis统一管理会话信息。
首先在pom.xml中引入redis和session的相关依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

在配置文件中添加redis配置信息

spring.redis.host=127.0.0.1
spring.redis.port=6379

这样springboot就会自动把session信息存入redis之中了,代码都不需要改动,是不是很简单。springbott默认的session过期时间是30分钟,如果需要修改,需新增自定义类

@Component
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisSessionConfig {

}

这样基于cookie的分布式会话改造就完成了。
调用后发现redis中会存入以下的key

 1)  "spring:session:sessions:d228adc8-b16b-4486-b628-3df20ec6fb37"
 2)  "spring:session:sessions:expires:d228adc8-b16b-4486-b628-3df20ec6fb37"
 3)  "spring:session:expirations:1565977370000"

另外,公司有同事的处理方案是在nginx配置ip_hash,使指定IP固定分发到指定的服务端,这样也能保证session的稳定,但缺点是当其中某一个服务器挂了,那么这一IP段的用户都访问不了了,所以还是不太推荐的