分布式和集群的Session共享问题


首先在进入主题之前,我们先复习以下 Cookie 与 Session

  • 何为 Cookie
    1、Cookie是服务器通知客户端保存键值对的一种技术。同时客户端保存了Cookie之后,每次请求都会发送给服务器。每个Cookie的大小不能超过4kb。
    2、Cookie 是保存在客户端的。

  • Cookie 的 工作机制
    Cookie的创建

服务器端返回 Cookie 信息给浏览器

Java 代码:response.addCookie(cookie 对象);
HTTP 响应消息头:Set-Cookie: Cookie 的名字=Cookie 的值

浏览器接收到服务器端返回的 Cookie,以后的每一次请求都会把 Cookie 带上

HTTP 请求消息头:Cookie: Cookie 的名字=Cookie 的值

  • 何为 Session 会话
    1、Session就是一个接口(HttpSession),保存在服务器。
    2、Session 会话,使用来维护一个客户端与服务器之间关联的一种技术。
    3、每一个客户端都有自己的一个Session会话。
    4、Session 会话中,通常用来保存用户登录之后的信息。

  • Session 的工作机制
    Session 的工作机制

获取 Session 对象:request.getSession()

检查当前请求是否携带了 JSESSIONID 这个 Cookie :

  • 带了:根据这个 JSESSIONID 在服务器端查找对应的 Session 对象
    • 能找到:就把找到的 Session 对象返回
    • 没找到:新建 Session 对象返回,同时返回 JSESSIONID 的 Cookie
  • 没带:新建 Session 对象返回,同时返回 JSESSIONID 的 Cookie

好啦,现在进入主题~

一、Session 共享问题的体现

在分布式和集群环境下,每个具体模块运行在单独的 Tomcat 上,而 Session 是被不同 Tomcat 所“区隔”的,所以不能互通,会导致程序运行时,用户会话数据发生错误。有的服务器上有,有的服务器上没有。

二、解决方案

1、Session 同步

Session同步
问题 1:造成 Session 在各个服务器上“同量”保存。TomcatA 保存了 1G 的 Session 数据,TomcatB 也需要保存 1G 的 Session 数据。数据量太大的会导 致 Tomcat 性能下降。
问题 2:数据同步对性能有一定影响。

2、将 Session 数据存储在 Cookie 中

做法:所有会话数据在浏览器端使用 Cookie 保存,服务器端不存储任何 会话数据。

  • 好处:
    • 服务器端大大减轻了数据存储的压力。不会有 Session 不一致问题 .
  • 缺点:
    • Cookie 能够存储的数据非常有限。一般是 4KB。不能存储丰富的数据。
    • Cookie 数据在浏览器端存储,很大程度上不受服务器端控制,如果浏 览器端清理 Cookie,相关数据会丢失。

3、反向代理 hash 一致性

反向代理 hash 一致性

  • 问题 1:具体一个浏览器,专门访问某一个具体服务器,如果服务器宕机, 会丢失数据。存在单点故障风险。
  • 问题 2:仅仅适用于集群范围内,超出集群范围,负载均衡服务器无效。

4、后端统一存储 Session 数据(重点)

后端存储 Session 数据时,一般需要使用 Redis 这样的内存数据库,而一 般不采用 MySQL 这样的关系型数据库。原因如下:

	Session 数据存取比较频繁。内存访问速度快。 
	Session 有过期时间,Redis 这样的内存数据库能够比较方便实现过期释放。
  • 该解决方式的优点:
    • ①访问速度比较快。虽然需要经过网络访问,但是现在硬件条件已经能够达到网络访问比硬盘访问还要快。
    • ②Redis 可以配置主从复制集群,不担心单点故障。

三、使用 Spring Session 实现 Session 共享

注意:这里是在 SpringBoot 环境下使用!!!

1、 创建 spring-session-a 和 spring-session-b 两个工程
spring-session-a 工程
spring-session-b 工程

2、在两个工程 的 pom.xml 中引入依赖

        <!-- SpringBoot 整合 redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- SpringBoot 整合 Spring Session -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

3、编写两个工程的启动类

spring-session-a 工程的启动类

@SpringBootApplication
public class  SpringSessionAApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSessionAApplication.class, args);
    }

}

spring-session-b 工程的启动类

@SpringBootApplication
public class SpringSessionBApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSessionBApplication.class, args);
    }

}

4、编写各自的 application.properties 配置文件

spring-session-a 工程

# 配置 redis 的主机地址
spring.redis.host=192.168.232.151

# 配置用来存储 Session 的数据库的类型
spring.session.store-type=redis
        
# 应用名称
spring.application.name=spring-session-a

# 应用服务 WEB 访问端口
server.port=1000

spring-session-b 工程

# 配置 redis 的主机地址
spring.redis.host=192.168.232.151

# 配置用来存储 Session 的数据库的类型
spring.session.store-type=redis

# 应用名称
spring.application.name=spring-session-b

# 应用服务 WEB 访问端口
server.port=2000

5、编写各自的 controller

spring-session-a 的 controller

@RestController
public class SessionAController {

    @RequestMapping("/test/session/save")
    public String saveSession(HttpSession session){

        session.setAttribute("king","get-king");

        return "数据存入 Session 域中";
    }
}

spring-session-b 的 controller

@RestController
public class SessionBController {

    @RequestMapping("/test/session/get")
    public String getSession(HttpSession session){

        String value = (String) session.getAttribute("king");

        return value;
    }
}

6、运行各自的启动类,访问测试

在Session域中存数据
当 Session 中存入值时,查看 Redis 数据库中所存入的值:
Redis 数据库中所存入的值

查看 Redis 所存入的数据的类型与值:
查看 Redis 所存入的数据的类型与值

从Session域中取数据

四、Spring Session 的原理

Spring Session的原理
查看源码 SessionRepositoryFilter
Spring Session源码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值