分布式Session的几种解决方案

前言

Session应用在Web应用程序中,用于存储用户的会话信息,最常见的是保存登录信息,如果应用是单机部署,那session就会被存储在应用服务器中,而对于分布式系统来说,是如何处理的呢,这篇文章会对相关知识简单分析。

  1. session在单体应用中的使用
  2. 分布式session的解决方案

单体应用中的session

如果我们只部署一个单体应用服务,也就只存在一个Web服务器,因此所有的Session都存储在一起,所以此时的session是非常容易管理的,下面是在SpringBoot中来操作Session的简单示例。

typescript 复制代码
//设置session
@GetMapping("setSession")
public void setSession(HttpServletRequest request){
    request.getSession().setAttribute("name","hg");
}
//获取session
@GetMapping("getSession")
public String getSession(HttpServletRequest request){
    return (String) request.getSession().getAttribute("name");
}

分布式session

对于分布式系统而言,因为部署了多台服务,不同的服务维护的session内容是不一致的,比如在部署时,同一套订单系统部署了两台服务,用户在请求时随机请求其中一台服务,如果直接使用上面的方式获取session,就会出现部分请求无法获取session的情况。

这时就要考虑分布式session的解决方法,目前常见的解决方案有Session复制、Session粘带、集中性Session管理等,本文只介绍比较常用的集中性Session管理这种方案的代码示例。

  1. Session同步

通过修改tomcat的配置,让所有tomcat之间的session进行同步,这样就可以实现不同Web容器的能拿到相同的session,这种最明显的缺点就是每台tomcat服务器都保存一份全量数据,浪费服务器内存,并且会增加数据传输的开销。

  1. Session粘带

这种方式是将session依旧保存在每一台服务器上,然后通过nginx负载均衡将相同ip请求转发到同一台服务器上,当然也可以根据业务id,将相同的业务id每次都访问同一台服务器,这样就不会和代码产生耦合,需要注意的是如果入口ip是同一个则就会变成单点系统了,所以需要根据实际情况选择。

此外,这种方式存储的session依旧是存储在web服务器上,如果服务器重启对客户端用户会有影响;如果增加或减少机器,需要重新计算哈希,也会对客户端请求产生影响,比如之前业务id是100,有2台机器,根据余数判断该id请求哪台服务器,如果增加了一台服务器,就会导致原本id=100应该请求服务器2的,现在请求到服务器1上了,就会获取数据失败。

  1. 集中性Session管理

这种方式就是将session存储在第三方数据库中,比如mysql或者redis中,下面看一下由Spring Cloud提供的基于Redis的Session管理方案。

3.1引入依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

3.2 增加配置

yaml 复制代码
#端口
server:
  port: 9999
​
#redis配置
spring:
  redis:
    database: 0
    host: localhost
    port: 6379
​
​

3.3启动类增加配置

less 复制代码
//设置session过期时间60秒,默认值1800秒
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60)
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3.4测试类

typescript 复制代码
    @GetMapping("setSession")
    public void setSession(HttpServletRequest request){
        request.getSession().setAttribute("name","hg");
    }
    @GetMapping("getSession")
    public String getSession(HttpServletRequest request){
        return (String) request.getSession().getAttribute("name");
    }

3.5查看redis上的数据

相关推荐
我是谁的程序员2 小时前
Windows / Linux / Mac 上不用 Xcode 把 IPA 上传到 App Store,upload 命令详解
后端·ios
凌涘2 小时前
JWT 登录鉴权 Demo 拆解
后端
JimmtButler3 小时前
从 Java 到 JS:我终于把闭包想明白了
javascript·后端
带多刺的玫瑰3 小时前
Leecode#4刷题之寻找两个正序数组的中位数
java·前端·算法
阿无,3 小时前
布隆过滤器
java·算法·哈希算法
掘金者阿豪3 小时前
Codex 怎么突然变慢了?一个需求跑几十分钟,我才发现它的工作方式已经变了
前端·后端
Pocker_Spades_A3 小时前
飞算JavaAI 48分钟能做完Java全栈项目吗?
java·springboot·#ai编程·#飞算javaai·#java代码生成·#aicoding模型·#java开发
Zadig3 小时前
Zadig 全面支持 CRD,至此所有 K8s 资源类型均可一键发布!
后端·devops
得物技术3 小时前
EP-Harness:从个人 AI Coding 到团队级 Agent 工作流|得物技术
后端·程序员·架构
用户125758524363 小时前
对象存储 URL 为什么别到处拼:后台附件预览要验这一层
后端·go·ai编程