侧边栏壁纸
  • 累计撰写 101 篇文章
  • 累计创建 89 个标签
  • 累计收到 9 条评论

分布式session - 几种解决方案

bearjun
2021-06-22 / 0 评论 / 1 点赞 / 1,455 阅读 / 2,746 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-06-22,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

在分布式环境中,我们往往需要考虑很多,不仅仅是原来单体应用的思路,要转变新的思路。数据来源于不同的服务端,产生结构一致的数据,怎么保证数据的一致性,往往是我们值得思考的。
分布式锁 - 几种解决方案 :https://bearjun.com/java/421.html
分布式限流 - 几种解决方案 :https://bearjun.com/java/383.html
接口的幂等性操作: https://bearjun.com/java/375.html

session共享问题

82233-z0fbnvl987.png
众所周知,session都只是存在当前的域名下,并且是当前的服务中。当分布式环境中,服务器可能存在多台,并且服务之间的跳转会在多个域名中反复跳转。

session复制

96277-jl4rf9vi2n.png
具体操作可以看这个文章:https://blog.csdn.net/wlwlwlwl015/article/details/48160433

优点

  • web-server(Tomcat)原生支持,只需要修改配置 文件

缺点

  • 大型分布式集群情况下,由于所有web-server都全 量保存数据,所以此方案不可取。
  • 任意一台web-server保存的数据都是所有web- server的session总和,受到内存限制无法水平扩展 更多的web-server
  • session同步需要数据传输,占用大量网络带宽,降 低了服务器群的业务处理能力

客户端存储

64834-ggxvqgs1cwf.png
这个只是提供一个思路,应该没有这么用的吧。

优点

  • 服务器不需存储session,用户保存自己的session信息到cookie中。节省服务端资源

缺点

  • 每次http请求,携带用户在cookie中的完整信息, 浪费网络带宽
  • session数据放在cookie中,cookie有长度限制 4K,不能保存大量信息
  • session数据放在cookie中,存在泄漏、篡改、窃取等安全隐患

hash一致性

55518-qxws07xsav.png
81970-yccde7f00pg.png
这个主要的缺点问题也不是很大,因为session本来都是有有效期的。所以这两种反向代理的方式可以使用。
这个主要就是用nginx的ip_hash绑定到唯一的一个服务器,然后让自己的请求一直请求到该服务器。

upstream aaa {
	ip_hash;
	server xx.xxx.xx.x:8080;
	Server xx.xxx.xx.x:8081;
}
server {
	listen 80;
	server_name www.bearjun.com;
	#root /usr/local/nginx/html;
	#index index.html index.htm;
	location / {
		proxy_pass http:xx.xxx.xx.x;
		index index.html index.htm;
	}
}

优点

  • 只需要改nginx配置,不需要修改应用代码
  • 负载均衡,只要hash属性的值分布是均匀的,多台web-server的负载是均衡的
  • 可以支持web-server水平扩展(session同步法是不行 的,受内存限制)

缺点

  • session还是存在web-server中的,所以web-server重 启可能导致部分session丢失,影响业务,如部分用户 需要重新登录
  • 如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session

统一存储(spring Session)

99359-gg8scw8yk6g.png
以下缺点可通过spring session解决。

Spring Session

官方文档地址:https://docs.spring.io/spring-session/docs/2.5.0/reference/html5/

  • 导入maven
<dependency>
     <groupId>org.springframework.session</groupId>
     <artifactId>spring-session-data-redis</artifactId>
</dependency>
  • 配置spring.session
# 存储方式redis/DB/MongDB...
spring.session.store-type=redis 
# 超时时间,默认是30m
server.servlet.session.timeout=30m
# Sessions刷新方式
spring.session.redis.flush-mode=on_save 
# session存储的前缀
spring.session.redis.namespace=spring:session 
  • 配置redis信息
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.port=6379 # Redis server port.
  • 主配置类添加注解
/**整合redis作为session存储*/
@EnableRedisHttpSession
public class Startup extends SpringBootServletInitializer {
	public static void main(String[] args) {
		SpringApplication.run(Startup.class);
	}
}
  • 自定义配置
@Configuration
public class SessionConfig {

    // 把session的作用域放大,例如auth.bearjun.com和berajun.com的session可以实现共享
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setDomainNamePattern("bearjun.com");
        return serializer;
    }

    // 序列化存储的数据
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

注意:要存储的对象一定要Serializable接口

优点

  • 没有安全隐患
  • 可以水平扩展,数据库/缓存水平切分即可
  • web-server重启或者扩容都不会有session丢失

缺点

  • 增加了一次网络调用,并且需要修改应用代码;如将所有的getSession方法替换为从Redis查数据的方式。redis获取数据比内存慢很多。
1

评论区