← 返回题目列表

分布式环境下 Session 怎么共享?Session 复制、粘性会话、集中存储各有什么优劣?

高频 中等 第 2 / 23 题 更新于 2026/08/03
分布式SessionSession共享Spring Session粘性会话

简化版

单机时 Session 存在服务器内存里没问题,但集群(多台服务器)时,用户第一次请求在服务器 A 创建了 Session,第二次请求被负载均衡分到服务器 B——B 上没有这个 Session,用户就「掉登录」了。这就是分布式 Session 问题。解决方案有几种:① 粘性会话(Sticky Session)——负载均衡按用户「固定分配」到同一台服务器(如按 IP hash),保证一个用户的请求都落到同一台;简单但服务器宕机会丢 Session、负载可能不均;② Session 复制(Replication)——每台服务器把自己的 Session 复制同步给其他所有服务器(每台都有全量 Session);不丢 Session 但复制开销大、占内存、服务器多了不可扩展③ 集中存储(推荐)——把 Session 存到外部的共享存储(如 Redis),所有服务器都从 Redis 读写 Session;任何服务器都能拿到 Session、服务器无状态、可水平扩展,是主流方案(Spring Session + Redis 一行配置搞定);④ 客户端存储(JWT)——干脆不用服务端 Session,用 JWT 把状态放客户端(无状态、天然分布式,但有 JWT 的失效难题)。核心:粘性会话简单但不可靠、复制不可扩展、集中存储(Redis)是主流、JWT 是无状态替代。

详细版

分布式 Session 方案对比

方案原理优点缺点
粘性会话同用户固定一台服务器简单、无额外存储宕机丢 Session、负载不均
Session 复制各服务器互相同步 Session不丢 Session复制开销大、不可扩展
集中存储(Redis)Session 存 Redis,共享无状态、可扩展、可靠依赖 Redis、有网络开销
客户端(JWT)状态放客户端 Token无状态、天然分布式JWT 失效难、Token 变大
// Spring Session + Redis(集中存储,最主流,几乎零代码)
// 1. 引入依赖
//    spring-session-data-redis + spring-boot-starter-data-redis
// 2. 配置
//    spring.session.store-type=redis
// 3. 加注解(或 Spring Boot 自动配置)
@EnableRedisHttpSession   // 开启 Redis 存储 Session
public class SessionConfig { }

// 之后代码不变,还是用 HttpSession
session.setAttribute("user", user);   // 底层存到 Redis(所有服务器共享)
User u = (User) session.getAttribute("user");  // 从 Redis 读
// → 用户请求到任何一台服务器,都能从 Redis 拿到 Session
分布式 Session 问题:
  用户 → 负载均衡 → 服务器A(创建 Session,存 A 的内存)
  用户再请求 → 负载均衡 → 服务器B(B 内存里没这个 Session)
  → 用户"掉登录"(Session 找不到)

集中存储解决:
  服务器A、B 都从 Redis 读写 Session
  → 用户请求到 A 或 B,都能从 Redis 拿到 Session(共享)

⚠️ 分布式 Session 的主流答案是「集中存储(Redis)」——它让服务器「无状态」,是水平扩展的关键。粘性会话虽然简单,但有致命缺陷:服务器宕机,落在它上面的所有用户 Session 都丢了(用户全部掉登录),且负载可能不均(某台被分到很多长会话用户)。Session 复制在服务器少时能用,但每台都存全量 Session(占内存)、每次 Session 变化要同步给所有服务器(复制风暴),服务器越多越不可扩展(N 台要 N-1 次复制)。而集中存储把 Session 从「服务器内存」搬到「外部共享存储(Redis)」——服务器本身不存 Session(无状态),任何服务器都能从 Redis 读写,所以可以随意加减服务器(水平扩展)、某台宕机不影响 Session。Spring Session + Redis 让这个方案几乎零成本(加个依赖、加个注解、配一下 Redis,代码里还是用 HttpSession,底层自动存 Redis)。所以现代分布式系统要么用 Redis 集中存 Session、要么用 JWT 无状态,很少用粘性会话或复制。

完整版教学

一、问题:集群下 Session 找不到

先理解分布式 Session 问题:

单机时的 Session(没问题):
  用户登录 → 服务器创建 Session(存在服务器内存)
  浏览器存 Session ID(Cookie: JSESSIONID)
  后续请求带 Session ID → 服务器用它找到 Session → 认得用户

集群时的问题(多台服务器):
  用户 → 负载均衡 → 服务器A(登录,Session 存 A 的内存)
  用户再请求 → 负载均衡 → 分到服务器B
  → B 的内存里没有这个 Session!
  → B 找不到 Session → 用户"掉登录"(以为没登录)

根源:
  Session 存在单台服务器的内存里
  但负载均衡可能把同一用户的请求分到不同服务器
  → 其他服务器没有这个 Session

所以分布式 Session 问题 = Session 存单机内存、集群下其他服务器拿不到
  → 用户请求分到没有 Session 的服务器 → 掉登录

分布式 Session 问题——单机时 Session 存服务器内存没问题(用 Session ID 找到)。集群时:用户在服务器 A 登录(Session 存 A 内存)、再请求被分到服务器 B、B 内存里没这个 Session、找不到、用户掉登录。根源:Session 存单台服务器内存、负载均衡可能把同一用户分到不同服务器、其他服务器没有这个 Session。理解「分布式 Session 问题:单机 Session 存内存没问题、集群时用户在 A 登录 Session 存 A 内存、再请求分到 B 找不到 Session 掉登录;根源 Session 存单机内存集群下其他服务器拿不到」,就理解了问题。

二、粘性会话

粘性会话(Sticky Session)——把用户固定到一台服务器:

粘性会话(Sticky Session / Session Affinity):
  负载均衡"按用户固定分配"到同一台服务器
  → 保证一个用户的所有请求都落到同一台
  → 那台服务器一直有这个用户的 Session

实现(负载均衡的策略):
  ① 按 IP hash:同一 IP 的请求分到同一台
  ② 按 Cookie:负载均衡记住"这个用户分到哪台"(如加个 route cookie)
  → Nginx 的 ip_hash、或基于 cookie 的会话保持

优点:
  ① 简单——不用额外存储(Session 还在服务器内存)
  ② 无 Session 同步/存储开销

缺点(致命):
  ① ★ 服务器宕机 → 落在它上面的所有用户 Session 都丢了
     → 那些用户全部掉登录
  ② 负载可能不均——某台被分到很多长会话用户
  ③ 扩缩容时 Session 会乱(加减服务器,用户重新分配)

适用:
  简单场景、能容忍宕机丢 Session、服务器稳定
  → 不推荐用于要求高可用的系统

所以粘性会话简单但不可靠(宕机丢 Session、负载不均)

粘性会话(Sticky Session)——负载均衡按用户固定分配到同一台服务器(保证一个用户所有请求落同一台、那台一直有 Session)。实现:按 IP hash(Nginx ip_hash)或按 Cookie(会话保持)。优点:简单(不用额外存储)、无同步开销。缺点(致命):① 服务器宕机落在它上面的所有用户 Session 都丢(全部掉登录)、② 负载可能不均、③ 扩缩容 Session 乱。适用简单场景、能容忍宕机丢 Session、不推荐高可用系统。理解「粘性会话:负载均衡按用户固定分配到同一台(IP hash/Cookie);优点简单无同步开销;缺点致命:服务器宕机丢所有 Session+负载不均+扩缩容乱;不推荐高可用」,就掌握了粘性会话。

三、Session 复制

Session 复制(Replication)——服务器间互相同步 Session:

Session 复制(Session Replication):
  每台服务器把自己的 Session 复制/同步给其他所有服务器
  → 每台服务器都有"全量 Session"(所有用户的)
  → 用户请求到任何一台,都能找到 Session

实现:
  Tomcat 的集群 Session 复制(DeltaManager / BackupManager)
  → 通过组播/单播在服务器间同步 Session 变化

优点:
  ① 不丢 Session——每台都有全量,某台宕机其他还有
  ② 用户请求到任何一台都能找到

缺点(不可扩展):
  ① ★ 复制开销大——每次 Session 变化要同步给所有服务器
     N 台服务器 → 每次变化要复制 N-1 次
     → 服务器越多,复制流量越大(复制风暴)
  ② 占内存——每台都存全量 Session(N 台存 N 份)
  ③ 不可扩展——服务器数量增加,复制成本急剧上升
     → 只适合"少量服务器"(如 2-4 台)

适用:
  服务器数量少、Session 数据小、要不丢 Session
  → 服务器多了就不行(复制风暴)

所以 Session 复制不丢 Session 但复制开销大、不可扩展

Session 复制(Replication)——每台服务器把自己的 Session 复制同步给其他所有服务器(每台都有全量 Session、用户请求到任何一台都能找到)。实现:Tomcat 集群 Session 复制(DeltaManager/BackupManager,组播/单播同步)。优点:不丢 Session(每台都有全量)、任何一台都能找到。缺点(不可扩展):① 复制开销大(每次 Session 变化同步给所有服务器、N 台复制 N-1 次、复制风暴)、② 占内存(每台存全量)、③ 不可扩展(服务器多复制成本急剧上升)。适用服务器少(2-4 台)。理解「Session 复制:每台把 Session 同步给其他所有服务器(每台全量);优点不丢 Session;缺点不可扩展:复制开销大(N 台复制 N-1 次复制风暴)+占内存+服务器多不行;只适合少量服务器」,就掌握了 Session 复制。

四、集中存储(推荐)

集中存储(Redis)——把 Session 存外部共享存储,主流方案:

集中存储(Centralized Session Storage):
  把 Session 从"服务器内存"搬到"外部共享存储"(如 Redis)
  → 所有服务器都从这个共享存储读写 Session
  → 服务器本身不存 Session(无状态)

原理:
  用户请求到服务器A → A 从 Redis 读/写 Session(用 Session ID 找)
  用户请求到服务器B → B 也从 Redis 读/写同一个 Session
  → 所有服务器共享 Redis 里的 Session

优点(主流原因):
  ① ★ 服务器无状态——不存 Session,可以随意加减(水平扩展)
  ② 可靠——某台服务器宕机不影响 Session(Session 在 Redis)
  ③ 可扩展——加服务器不增加 Session 存储成本(都用一个 Redis)
  ④ Redis 快、支持过期(Session 过期自动清理)

缺点:
  ① 依赖 Redis(Redis 挂了 Session 都没了 → Redis 要高可用)
  ② 有网络开销(每次读写 Session 访问 Redis,但 Redis 快、可忽略)

Spring Session + Redis(几乎零成本):
  引入 spring-session-data-redis
  配置 spring.session.store-type=redis
  → 代码不变(还是用 HttpSession),底层自动存 Redis
  → 一行配置,Session 就集中存储了

所以集中存储(Redis)是主流:无状态、可扩展、可靠、Spring Session 零成本

集中存储(Redis)——把 Session 从服务器内存搬到外部共享存储(Redis),所有服务器从 Redis 读写(服务器本身不存 Session、无状态)。原理:用户请求到任何服务器都从 Redis 读写同一个 Session。优点(主流原因):① 服务器无状态可随意加减(水平扩展)、② 可靠(某台宕机不影响 Session)、③ 可扩展(加服务器不增加存储成本)、④ Redis 快支持过期。缺点:依赖 Redis(要高可用)、有网络开销(可忽略)Spring Session + Redis 几乎零成本(引入依赖+配置、代码不变还是用 HttpSession、底层自动存 Redis)。理解「集中存储 Redis:Session 存 Redis 所有服务器共享(服务器无状态);优点无状态可水平扩展+可靠(宕机不影响)+可扩展+Redis 快;缺点依赖 Redis;Spring Session+Redis 零成本(代码不变底层存 Redis);主流方案」,就掌握了集中存储。

五、客户端存储(JWT)

客户端存储(JWT)——不用服务端 Session,状态放客户端:

客户端存储(JWT):
  干脆不用服务端 Session——把状态放客户端(JWT Token)
  → 用户信息 + 签名都在 Token 里,客户端存、每次请求带
  → 服务端不存 Session(无状态、天然分布式)

原理:
  登录 → 服务端签发 JWT(含用户信息)→ 客户端存
  后续请求带 JWT → 服务端验签 + 查过期 → 认得用户
  → 服务端不存任何东西,任何服务器都能验 JWT(无状态)

优点:
  ① 无状态——服务端不存 Session,天然分布式(任何服务器都能验)
  ② 无需共享存储(不用 Redis 存 Session)
  ③ 易水平扩展

缺点:
  ① JWT 失效难——签发后无法主动失效(见登出题)
     要黑名单(又引入状态)或短过期
  ② Token 变大——用户信息都在 Token 里,每次请求带(带宽)
  ③ 安全——Token 泄露风险(要 HTTPS、短过期)

JWT vs Redis 集中存储:
  Redis:有状态(存 Redis),能主动失效,但依赖 Redis
  JWT:无状态,天然分布式,但失效难
  → 看是否需要"主动失效"和"服务端存储"

所以 JWT 是无状态的分布式方案(不用 Session),但有失效难题

客户端存储(JWT)——不用服务端 Session,把状态放客户端(JWT Token,用户信息+签名在 Token 里、客户端存、每次请求带、服务端不存 Session、无状态、天然分布式)。原理:登录签发 JWT、后续请求验签查过期认得用户(服务端不存、任何服务器都能验)。优点:无状态天然分布式、无需共享存储、易扩展。缺点:JWT 失效难(签发后无法主动失效、要黑名单或短过期)、Token 变大、安全风险。JWT vs Redis:Redis 有状态能主动失效但依赖 Redis、JWT 无状态天然分布式但失效难。理解「客户端存储 JWT:不用服务端 Session、状态放客户端 Token(服务端不存无状态天然分布式);优点无状态易扩展无需共享存储;缺点 JWT 失效难(要黑名单/短过期)+Token 变大;vs Redis:Redis 有状态能失效、JWT 无状态但失效难」,就掌握了客户端存储。

六、选择与实践

总结分布式 Session 的选择:

选择(按需求):
  要简单、能容忍宕机丢 Session、服务器少 → 粘性会话(不推荐)
  服务器少(2-4 台)、要不丢 Session → Session 复制(有限场景)
  ★ 主流推荐 → 集中存储(Redis + Spring Session)
    → 无状态、可扩展、可靠、零成本
  无状态、REST API、天然分布式 → JWT(客户端存储)

现代主流做法:
  ① 传统 Session 场景(要用 HttpSession)→ Spring Session + Redis
     (代码不变、底层存 Redis、集中存储)
  ② 前后端分离 / REST API → JWT(无状态)
  → 很少用粘性会话或 Session 复制

实践建议:
  ① 用 Spring Session + Redis(集中存储,主流、零成本)
  ② 或用 JWT(无状态,前后端分离场景)
  ③ Redis 要高可用(Session 依赖它)
  ④ 别用粘性会话(宕机丢 Session)或复制(不可扩展)

核心总结:
  分布式 Session 问题:Session 存单机、集群下其他服务器拿不到
  方案:粘性会话(简单不可靠)/复制(不可扩展)/集中存储 Redis(主流)/JWT(无状态)
  主流:Redis 集中存储(Spring Session 零成本)或 JWT

分布式 Session 选择:要简单能容忍宕机丢 Session→粘性会话(不推荐)、服务器少要不丢→复制(有限场景)、主流推荐→集中存储(Redis+Spring Session,无状态可扩展可靠零成本)、REST API 无状态→JWT。现代主流:传统 Session 场景用 Spring Session+Redis(代码不变底层存 Redis)、前后端分离用 JWT、很少用粘性会话或复制。实践:用 Spring Session+Redis 或 JWT、Redis 要高可用、别用粘性会话或复制。理解「选择:粘性会话(不推荐)/复制(有限)/集中存储 Redis(主流)/JWT(无状态);现代主流 Spring Session+Redis 或 JWT、很少用粘性会话或复制;Redis 要高可用」,就掌握了选择和实践。

记忆钩子:「分布式 Session 问题:Session 存单机内存、集群下用户请求分到其他服务器拿不到 Session 掉登录;方案:①粘性会话 Sticky Session(负载均衡按用户固定一台 IP hash/Cookie,简单但服务器宕机丢所有 Session+负载不均,不推荐)②Session 复制(每台同步给所有服务器每台全量,不丢 Session 但复制开销大 N 台复制 N-1 次复制风暴+占内存+不可扩展,只适合少量服务器)③★集中存储 Redis(Session 存 Redis 所有服务器共享、服务器无状态可水平扩展+可靠宕机不影响+Spring Session+Redis 零成本代码不变底层存 Redis,主流)④客户端 JWT(状态放客户端 Token 服务端不存无状态天然分布式,但失效难 Token 变大);主流:Redis 集中存储或 JWT,别用粘性会话/复制」

七、常见误区与追问

  • 误区:粘性会话是分布式 Session 的好方案。 有致命缺陷——服务器宕机会导致落在它上面的所有用户 Session 丢失(全部掉登录)、负载可能不均、扩缩容时 Session 会乱;只适合简单、能容忍宕机丢 Session 的场景;高可用系统应该用集中存储(Redis)或 JWT。
  • 误区:Session 复制适合大集群。 不适合——Session 复制每次 Session 变化要同步给所有服务器,N 台服务器每次变化要复制 N-1 次,服务器越多复制流量越大(复制风暴),且每台都存全量 Session(占内存);只适合少量服务器(2-4 台);大集群要用集中存储(一个 Redis 共享)。
  • 误区:用 Redis 存 Session 要大改代码。 不用——Spring Session + Redis 几乎零成本:引入 spring-session-data-redis 依赖、配置 spring.session.store-type=redis(或加 @EnableRedisHttpSession),代码里还是用 HttpSession(session.setAttribute/getAttribute 不变),底层自动把 Session 存到 Redis、所有服务器共享。
  • 误区:JWT 和 Redis 集中存储都是有状态的。 不同——Redis 集中存储是有状态的(Session 存在 Redis,服务端能主动删除/失效);JWT 是无状态的(状态在客户端 Token 里,服务端不存,任何服务器验签即可),天然分布式但 JWT 签发后无法主动失效(要黑名单或短过期);一个有状态能失效、一个无状态但失效难。
  • 追问:分布式环境下 Session 为什么会有问题,怎么解决? 单机时 Session 存在服务器内存里没问题;集群时,用户第一次请求在服务器 A 创建了 Session(存 A 内存),第二次请求被负载均衡分到服务器 B,B 内存里没有这个 Session,找不到就导致用户掉登录;解决方案:① 粘性会话(负载均衡把同用户固定到一台,简单但宕机丢 Session);② Session 复制(服务器间互相同步,不丢但不可扩展);③ 集中存储(Session 存 Redis 等外部共享存储,所有服务器共享,服务器无状态、可扩展、可靠,主流,Spring Session + Redis 零成本);④ JWT(状态放客户端,无状态、天然分布式)。
  • 追问:为什么集中存储(Redis)是分布式 Session 的主流方案? 因为它让服务器「无状态」——Session 从服务器内存搬到外部共享存储(Redis),服务器本身不存 Session,任何服务器都能从 Redis 读写同一个 Session;好处:① 可以随意加减服务器(水平扩展,加服务器不增加 Session 存储成本);② 某台服务器宕机不影响 Session(Session 在 Redis,其他服务器照样能拿到);③ Redis 快、支持过期(Session 自动清理);④ Spring Session + Redis 几乎零成本(代码不变);相比粘性会话(宕机丢 Session)和复制(不可扩展),集中存储可靠且可扩展。
  • 追问:Session 集中存储和 JWT 怎么选? Session 集中存储(Redis):有状态(Session 存 Redis),能主动失效(服务端删 Session)、支持并发会话控制、和传统 Session 编程模型一致(用 HttpSession),但依赖 Redis(要高可用);JWT:无状态(状态在客户端 Token),天然分布式(不用共享存储)、易水平扩展,但 JWT 签发后无法主动失效(要黑名单或短过期)、Token 变大;如果需要主动失效、并发会话控制、传统 Session 模型 → Redis;如果追求无状态、REST API、前后端分离、不想依赖 Redis → JWT;很多系统混用(JWT + Redis 黑名单)。

八、加强记忆

分布式 Session 问题:单机时 Session 存服务器内存没问题,但集群时用户在服务器 A 创建 Session(存 A 内存),再请求被分到服务器 B,B 内存里没这个 Session、用户掉登录。解决方案:① 粘性会话(Sticky Session)——负载均衡把同用户固定到一台(IP hash/Cookie),简单但服务器宕机丢所有 Session、负载不均(不推荐);② Session 复制(Replication)——每台服务器把 Session 同步给其他所有(每台全量),不丢 Session 但复制开销大(N 台复制 N-1 次、复制风暴)、占内存、不可扩展(只适合少量服务器);③ 集中存储(Redis,主流推荐)——Session 存 Redis,所有服务器共享,服务器无状态、可水平扩展、可靠(宕机不影响)、Spring Session + Redis 零成本(代码不变、底层存 Redis);④ 客户端存储(JWT)——状态放客户端 Token,服务端不存(无状态、天然分布式),但 JWT 失效难、Token 变大。现代主流:传统 Session 场景用 Spring Session + Redis、前后端分离用 JWT很少用粘性会话或复制。一句话「分布式 Session 问题:Session 存单机集群下其他服务器拿不到掉登录;粘性会话(固定一台,宕机丢 Session 不推荐)/Session 复制(互相同步,不可扩展复制风暴)/集中存储 Redis(共享,服务器无状态可扩展可靠,Spring Session 零成本,主流)/JWT(状态放客户端,无状态天然分布式但失效难);主流 Redis 集中存储或 JWT」。