数据与状态分离
理解这个概念之前,我们需要先搞明白两个词——「数据」和「状态」到底有什么区别?为什么把它们分开,扩容就变得轻松了?
数据 Data
持久化的、可共享的信息。存储在数据库、文件系统、对象存储中。多实例共享同一份数据源。
状态 State
运行时产生的、存在内存中的信息。每个进程/实例独立持有,无法直接共享。重启即丢失。
状态耦合 vs 状态分离
让我们通过一个具体例子,看两种设计的天壤之别。
每台服务器都存状态
状态外置到 Redis
扩容场景对比
同样是扩容请求量 10 倍,两种架构的操作天差地别。
❌ 耦合架构扩容
- 先评估每个实例的负载上限
- 计算需要新增几台机器
- 部署新机器,安装相同环境
- 配置负载均衡
- 测试请求是否会路由到新机器
- ⚠️ 如果用户 session 在旧机器,新机器读不到
- ⚠️ 需要 sticky session 或 session 复制
耗时:30-60 分钟,复杂且容易出错
✅ 分离架构扩容
- 打开 K8s/Docker Swarm 控制台
- 把副本数从 3 改成 10
- 按回车
耗时:30 秒,自动完成
原因:无状态服务可以随时启停,
新实例启动后自动从 Redis 读取状态
为什么分离就能轻松扩容?
核心原理:通过把「状态」从应用实例中抽离出来,让服务变成「无状态」的。
任意实例可处理请求
请求可以路由到任意一个实例,不需要关心「这个用户上次访问的是哪台机器」。因为所有状态都在外部存储。
秒级启停
实例挂了?直接 kill 掉,新实例 5 秒拉起。不需要迁移状态,因为状态本来就不在实例上。
流量自动均摊
负载均衡器可以随意选择最优实例。不存在「某台机器特别热」的问题。
故障隔离
一个实例崩溃不影响其他实例。用户请求自动被路由到健康实例,对用户无感知。
常见实现方式
把状态外置,这些是标配方案。
Redis - Session / 缓存
最常用的内存数据库,存储用户 Session、热点数据缓存。毫秒级读写,适合高频访问的场景。
MySQL - 业务数据
持久化的业务数据,用户信息、订单、配置等。关系型数据库保证数据一致性。
S3 / OSS - 文件存储
用户上传的文件、图片、视频等。分布式文件系统,提供海量存储和高可用。
❌ 这些是状态耦合的反模式
一句话总结
把「状态」当作「数据」来处理
数据存在 DB/Redis/OSS → 任何实例都能访问 →
服务变成「无状态」→
可以随意扩缩容 → 故障自动恢复 → 运维轻松
记住这个公式
无状态服务 + 外部存储 = 可水平扩展
什么时候该分离?
- 需要水平扩展(多实例)时
- 需要高可用(故障恢复)时
- 需要弹性伸缩(高峰期扩容)时
- 需要 Session 共享时