这里的核心概念是:会话共享存储(shared session storage)。
用户登录以后,服务器需要保存一些与该用户当前访问相关的状态,例如:
session_id: abc123
user_id: 9527
is_logged_in: true
shopping_cart: [商品A, 商品B]
expires_at: 2026-08-09 18:00
这些数据统称为用户会话(Session)。
浏览器通常只保存一个 Session ID:
Cookie: session_id=abc123
服务器收到请求后,再用这个 ID 从共享存储中查找完整的会话数据。
为什么需要共享存储?
假设系统有三台应用服务器:
┌→ 应用服务器 1
用户 → 负载均衡器 ├→ 应用服务器 2
└→ 应用服务器 3
如果会话只保存在服务器 1 的内存中:
- 用户登录请求被服务器 1 处理。
- 登录状态保存在服务器 1。
- 下一个请求被分配给服务器 2。
- 服务器 2 找不到会话,便认为用户没有登录。
共享存储让不同的应用服务器访问同一个数据存储系统。
"同一个共享存储"指的是同一个逻辑存储服务,不一定只有一台物理服务器。它也可能是 Redis 集群。
如果三台服务器都访问同一个会话存储,则无论请求落在哪台服务器上,都能取得相同的登录状态:
应用服务器 1 ─┐
应用服务器 2 ─┼→ 共享会话存储
应用服务器 3 ─┘
无论用户请求被分配到哪台应用服务器,服务器都会访问同一个会话,所以能够获得相同的会话数据。通常系统会选定一个共享会话存储。
关于数据存储系统
- 数据存储系统(Data Storage System):所有能够保存、读取和管理数据的系统的统称,范围很广,包括数据库、文件系统、对象存储和缓存等。
- 数据库(Database):一种结构化管理数据的数据存储系统,通常提供查询、更新、索引、事务或持久化等能力。
数据存储系统
├── 关系型数据库:MySQL、PostgreSQL
├── NoSQL 数据库:MongoDB、Redis
├── 缓存系统:Memcached
├── 文件系统
└── 对象存储:Amazon S3
在这里比较四类常见共享存储的选择:
- Redis:内存型键值数据存储,常用于共享会话和缓存。
- Memcached:内存缓存系统,适合保存可以丢失或重新生成的临时会话数据。
- 数据库:这里通常指关系型数据库,例如 MySQL、PostgreSQL,通过会话表保存数据。
- 其他共享存储系统:指任何能被所有应用服务器共同访问的存储系统。
Redis
Redis 是以内存为主的键值数据存储,数据通常采用下面的形式:
键:session:abc123
值:{
"user_id": 9527,
"is_logged_in": true
}
读取过程类似于:
GET session:abc123
Redis 很适合保存会话,因为它具有以下特点:
- 读取和写入速度快
- 可以为会话设置自动过期时间
- 支持持久化和复制
- 支持字符串、哈希、列表和集合等数据结构
- 比较容易构建高可用集群
例如,可以把会话设置为 30 分钟后过期:
SET session:abc123 "会话数据" EX 1800
如果用户在规定时间内没有继续访问,Redis 会自动删除该会话。
Memcached
Memcached 也是以内存为主的键值缓存系统:
键:session:abc123
值:序列化后的会话数据
它的主要特点是:
- 模型非常简单
- 读取和写入速度快
- 支持数据过期
- 容易水平扩展
- 通常不负责持久化数据
Memcached 更像一个纯缓存。服务器重启、缓存被淘汰或节点发生故障时,会话数据可能消失,用户可能需要重新登录。
缓存(Cache)是位于数据使用者和原始数据源之间的一层高速临时存储,用来保存近期使用过或经常使用的数据副本。缓存通常保存可重新获取或重新计算的数据;但 Redis、Memcached 用作会话存储时,会话数据也可能只存在于其中。
Redis 和 Memcached 的主要区别可以概括为:
| 对比项 | Redis | Memcached |
|---|---|---|
| 数据模型 | 多种数据结构 | 简单键值 |
| 持久化 | 支持 | 通常不支持 |
| 复制和高可用 | 支持 | 能力有限 |
| 数据过期 | 支持 | 支持 |
| 典型用途 | 会话、缓存、计数器、队列 | 简单高速缓存 |
| 会话丢失风险 | 可通过持久化和复制降低 | 相对更高 |
在现代系统中,Redis 通常是共享会话存储的常见选择。
数据库
也可以把会话保存在 MySQL、PostgreSQL 等关系型数据库中:
| session_id | user_id | data | expires_at |
|---|---|---|---|
| abc123 | 9527 | {...} |
2026-08-09 18:00 |
所有应用服务器都连接到这个数据库,因此都可以读取同一份会话。
优点包括:
- 数据可以持久保存
- 事务和一致性能力较强
- 系统可能已经有数据库,不需要引入新组件
- 运维方式比较熟悉
缺点包括:
- 通常比内存存储慢
- 大量会话读写会增加数据库压力
- 会话的访问频率通常很高,可能影响核心业务查询
- 需要定期清理过期记录
数据库适合规模较小的系统,或者会话不能轻易丢失的场景。随着访问量增加,通常会把会话迁移到 Redis 等独立存储。
其他共享存储
"其他共享存储"不是某一种特定产品,而是指任何能被所有应用服务器共同访问的存储系统,例如:
- 分布式键值数据库
- 云服务商提供的托管 Redis
- 分布式缓存集群
- 专用会话服务
- 共享文件系统
- 某些支持过期机制的 NoSQL 数据库
它们必须满足一个关键条件:应用服务器之间看到的是同一份会话数据。
共享文件系统理论上也能保存会话,但文件锁、并发访问、延迟和扩展性往往比较麻烦,通常不是首选。
应该怎样选择?
一般可以这样判断:
- 小型应用:数据库足够简单实用。
- 普通生产系统:通常选择 Redis。
- 只需要高速临时缓存,并且允许用户偶尔重新登录:可以选择 Memcached。
- 大规模或多地域系统:使用高可用 Redis 集群、分布式键值数据库或专门的会话服务。
这里最重要的并不是具体选择哪个产品,而是让应用服务器保持无状态:
应用服务器不拥有会话
应用服务器只是读取和修改共享存储中的会话
这样,任何一台服务器都可以处理任何用户的请求,也可以随时增加、替换或关闭应用服务器。