SpringSession - 分布式Session解决方案及SpringSession基本使用

分布式Session的几种解决方案

1、Session复制

SpringSession - 分布式Session解决方案及SpringSession基本使用_第1张图片
Tomcat服务器互相同步session。
优点:
web-server (Tomcat) 原生支持,只需要修改配置文件
缺点:
1、session同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力
2、任意一台web-server保存的数据都是所有web-server的sesdion总和,受到内存限制无法水平扩展更多的web-server
3、大型分布式集群情况下,由于所有web-server都全量保存数据,所以此方案不可取。

2、客户端存储

SpringSession - 分布式Session解决方案及SpringSession基本使用_第2张图片
将session存储在cookie中。
优点:
服务器不需存储session,用户保存自己的session信息到cookie中,节省服务端资源。
缺点:
这只是一种思路,不会使用该方式,具体原因如下:
1、每次http请求,携带用户在cookie中的完整信息,浪费网络带宽。
2、session数据放在cookie中,cookie有长度限制4K,不能保存大量信息。
3、session数据放在cookie中,存在泄漏、算改、窃取等安全隐患。

3、Hash一致性

利用ip_hash的一致性,浏览器不变,IP不变,让每一次访问都落在同一个服务器上。同时也可以配合id值,比如图中的sid=456的请求每次落在第一个服务器,sid=123的请求每次落在第二个服务器。
优点:
1、只需要改nginx配置,不需要修改应用代码。
2、负载均衡,只要hash属性的值分布是均匀的,多台web-server的负载是均衡的。
3、可以支持web-server水平扩展(session同步法是不行的,受内存限制)。
缺点:
1、session还是存在web-server中的,所以web-server重启可能导致部分session丢失,影响业务,如部分用户需要重新登录。
2、如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session。
但是以上缺点问题也不是很大,因为session本来都是有有效期的。所以这两种反向代理的方式可以使用。

4、统一存储

SpringSession - 分布式Session解决方案及SpringSession基本使用_第3张图片
session存储到数据库(Redis)中,每次都从数据库中获取。
优点:
1、没有安全隐患
2、可以水平扩展,数据库/缓存水平切分即可
3、web-server重启或者扩容都不会有session丢失
缺点:
增加了一次网络调用,并且需要修改应用代码;如将所有的getSession方法替换为从Redis查数据的方式,redis获取数据比内存慢很多
上面缺点可以用SpringSession完美解决

5、不同服务,子域Session共享

jsessionid这个cookie默认是当前系统域名的。当我们分拆服务,不同域名部署的时候,我们可以使用如下解决方案:
SpringSession - 分布式Session解决方案及SpringSession基本使用_第4张图片
第一次使用Session的时候,命令浏览器Cookie保存卡号(JESSIONID),以后浏览器访问哪个网站都会带上这个网站的cookie。
发卡的时候指定域名为父域名,即使是子域系统发的卡,也能让父域直接使用。
给父域发jesessionid卡,子域共享。比如给liuchengyin.com发卡,auth.liuchengyin.com、item.liuchengyin.com共享。

SpringSession的使用

SpringBoot整合SpringSession。官方文档:spring-session-data-redis文档
SpringSession - 分布式Session解决方案及SpringSession基本使用_第5张图片

1、引入spring-session-data-redis依赖

<!-- 整合SpringSession完成Session共享问题 -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
2、配置文件 - properties或yml

所有使用分布式Session的微服务都要配置,当然肯定还需要配置Redis相关的内容。比如在A服务中存储,在B、C服务中获取,A、B、C服务都需要配置。

# Session保存类型 - Redis
spring.session.store-type=redis
# Session过期时间 - 默认30分钟
server.servlet.session.timeout=30m
# 同时,也需要配置Redis连接信息
spring.redis.host=192.168.200.134
spring.redis.port=6379
3、配置Redis - 如果已经配置过则无需再配置
@EnableRedisHttpSession  // 使用RedisHttpSession,
public class Config {
	@Bean
	public LettuceConnectionFactory connectionFactory() {
		return new LettuceConnectionFactory(); 
	}
}
4、配置作用域和Session序列化
@Configuration
public class LiuchengyinSessionConfig {
    /**
     * 设置作用域
     */
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
		/*
			设置父域 - liuchengyin.com
			则xxx.liuchengyin.com都会共享
		*/
        cookieSerializer.setDomainName("liuchengyin.com");
        cookieSerializer.setCookieName("LCYSESSION");  // 自定义SessionId
        return cookieSerializer;
    }

    /**
     * JSON序列化 - 使用FastJson,需要引入Fastjson的依赖
     */
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
        return new GenericFastJsonRedisSerializer();
    }
}
5、正常调用session存储数据即可
public String saveData(HttpSession session, Long id){
    // 从数据库中查询数据
    User user = userDao.selectUserById(id);
    // 保存数据
    session.setAttribute("loginUser",user);
    return user;
}
6、查看Redis中保存的数据

SpringSession - 分布式Session解决方案及SpringSession基本使用_第6张图片

7、查看浏览器Cookie

在这里插入图片描述
此时就可以去.liuchengyin.com的子域也可以获取到session

SpringSession原理浅析

原理其实就是运用了装饰者模式。且Redis中的Session也有过期时间,和原生Session一致,会自动续期。

@EnableRedisHttpSession注解

导入了RedisHttpSessionConfiguration配置
SpringSession - 分布式Session解决方案及SpringSession基本使用_第7张图片
RedisHttpSessionConfiguration添加了RedisOperationsSessionRepository组件,即使用Redis操作session,session的增删改查封装类。即SessionRepository ====>>> 【RedisOperationsSessionRepository】
SpringSession - 分布式Session解决方案及SpringSession基本使用_第8张图片
RedisHttpSessionConfiguration继承自SpringHttpSessionConfiguration,可以在SpringHttpSessionConfiguration中看到一个过滤器SessionRepositoryFilter,即Session存储过滤器,每个请求过来都必须经过Filter
SpringSession - 分布式Session解决方案及SpringSession基本使用_第9张图片
1、创建Session的时候就自动从容器中获取了SessionRepository
2、原始的request和response都被包装成SessionRepositoryRequestWrapper和SessionRepositoryResponseWrapper
3、以后获取session,即通过reuqest.getSession()。就相当于调用wrappedRequest.getSession()。如果wrappedRequest.getSession()有自定义的实现,就相当于Session的获取方法改变了。
4、wrappedRequest.getSession()就是从SessionRepository获取到的。

你可能感兴趣的:(SpringBoot)