分布式环境下,如何实现session共享

发布时间 2023-03-27 14:59:45作者: 百里浅暮

为什么会出现这种session共享的解决方案?

随着互联网公司的项目在微服务和分布式的环境下进行的搭建,导致一个项目可能分别部署在几个甚至很多的服务器集群下,此时就会出现一个问题:

当用户进行一个session会话的时候,比如一个用户去登录项目,一般的大公司的项目都是有Nginx进行反向代理的,

Nginx常用的几种反向代理策略:

  1. 轮询策略
  2. 权重比例策略
  3. ip_hash策略
  4. 还可以自定义的策略

在Nginx的反向代理下,一般会把用户的请求分发到不同的服务器上,但是如果用户请求的请求是存放在该请求的服务器A上,那么该用户的sessionID就存储在该服务器上JVM的一个ConcurrentHashmap中,以sessionID为key。

但是如果此时用户请求的一个服务模块可能需要调用到服务器B,当用户发起请求的时候,此时的服务器B上并没有存储该用户的sessionID,所以就会再次让用户进行一个登陆操作。还有可能会导致用户本来就想完成一个下单操作,但是却还登陆了好几次的情况。

所以session共享方案在分布式环境和微服务系统下,显得尤其重要。

解决方案一:基于Nginx的ip_hash 负载均衡

通过ip地址标记用户,如果多次请求都是从同一个ip来的,那么就都分配到同一个服务器上。这样就不会出现负载均衡session问题了,处理手段也很简单。

具体实现:

需要你在Nginx.conf文件中进行对应的修改,根据自己的可用服务器

upstream backend{
    ip_hash;
    server 192.168.128.1:8080 ;
    server 192.168.128.2:8080 ;
    server 192.168.128.3:8080 down;
    server 192.168.128.4:8080 down;
 
}
server {
    listen 8081;
    server_name test.csdn.net;
    root /home/system/test.csdn.net/test;
    location ^~ /Upload/upload {
    proxy_pass http://backend;
 
    }
 
}

优点:

  • 配置简单,对应用无侵入性,不需要修改代码
  • 便于服务器水平扩展
  • 安全性较高

缺点:

  • 大量请求来之某个局域网,那么相当于就没有负载均衡了,存在单点负载高的风险
  • 如果只剩下一台服务器正好正常使用的,nginx就只能把请求交给该台服务器,但是这里却没有记录session,用户体验依然受影响。
  • 水平扩展过程中也会造成部分session失效

解决方案二:基于Tomcat的session复制

这个解决方案其实就是当用户请求的时候,把产生的sessionID给复制到系统所有的服务器中,这样就能保证当用户请求的时候从服务器A可能调用到服务器B上的模块的时候,也能保证服务B也有该用户的sessionID,这样就不会再次让用户进行再次登录操作了。也就解决问题了。

具体代码中如何实现session复制呢?

优点

  • 对应用无侵入性,不需要修改代码
  • 能适应各种负载均衡策略
  • 服务器重启或宕机不会造成session丢失
  • 安全性较高

缺点

  • session同步会有一定的延时
  • 占用内网宽带资源
  • 受制于内存资源,水平扩展能力差
  • 服务器数量不能太多
  • 序列化和反序列化消耗CPU资源

解决方案三:使用Redis做缓存session的统一缓存

这种方案呢,其实就是把每次用户的请求的时候生成的sessionID给放到Redis的服务器上。然后在基于Redis的特性进行设置一个失效时间的机制,这样就能保证用户在我们设置的Redis中的session失效时间内,都不需要进行再次登录。

如何进行代码的实现:

优点

  • 能适应各种负载均衡策略
  • 服务器重启或宕机不会造成session丢失
  • 安全性较高
  • 扩展能力强
  • 适合集群数量大时使用

缺点

  • 对应用有侵入,需要增加相关配置
  • 增加一次网络开销,用户体验降低
  • 序列化和反序列化消耗CPU资源

解决方案四:结合cookie

把session放到cookie中去,因为每次用户请求的时候,都会把自己的cookie放到请求中,所以这样就能保证每次用户请求的时候都能保证用户在分布式环境下,也不会再进行二次登陆。

 

参考: