理解 Redis 的复制、Sentinel 和 Cluster 之后,我们已经能够回答两个基础问题:Primary 故障时如何接管,单个 Primary 达到容量或吞吐上限后如何分片。但在真实项目中,技术负责人面对的通常不是一道“Sentinel 还是 Cluster”的单选题。

例如,前两篇中的“光光平台”可能同时把 Redis 用于文章缓存、登录会话、邮件任务和接口限流:

article:8848             文章缓存
session:user:1001        登录会话
queue:email              邮件任务
rate-limit:user:1001     限流状态

这些数据都能写进 Redis,却有完全不同的故障含义。文章缓存丢失后可以从 PostgreSQL 重建;会话丢失会让用户重新登录;邮件任务被淘汰可能让通知永远无法发送;限流状态失效则可能让突发流量直接进入下游服务。如果只根据总内存选择一套 Redis,再让所有业务共用它,架构图可能很简单,故障半径却会越来越大。

这里的故障域,是指可能因同一个故障而同时失效的一组资源,例如同一进程、主机、可用区或地域。

生产架构选型需要同时回答五类问题:Redis 的基础设施生命周期由谁负责,应用如何访问 Redis,节点或可用区故障后谁来接管,整个地域不可用时如何恢复,以及不同业务是否应该共享资源和故障域。本文沿着这五类问题,讨论自建 Redis Open Source、代理、托管服务、多可用区和跨地域方案的特点与边界。

本文继续使用同一个虚构的“光光平台”作为案例,不代表本站当前的实际生产部署。Primary-Replica 复制与 Sentinel 的故障转移机制已经在《Redis 高可用原理:Primary-Replica 复制、Sentinel 与故障转移》中展开,哈希槽、客户端重定向和在线扩缩容则见《Redis Cluster 原理:哈希槽、请求路由与在线扩缩容》。本文不重复这些协议细节,而把注意力放在生产组织方式和选型过程上。

1. Redis 生产选型需要回答哪些问题

Redis 架构并不是节点数量越多越好。增加节点能够减少某些单点故障,也会增加连接、拓扑、复制、监控和故障排查的复杂度。一个可执行的选型过程,应先把业务目标翻译成可以验证的系统约束。

1.1 先区分容量、可用性与灾难恢复

三个经常被混用的目标实际上相互独立:

目标 要回答的问题 常见机制
横向扩展 单个 Primary 装不下数据或无法承担写入时怎么办 Redis Cluster、托管分片
高可用 进程、主机或可用区故障后如何继续提供服务 Replica、Sentinel、分片级故障转移
灾难恢复 整个地域不可用或数据被破坏后如何恢复 跨地域副本、备份、切流与回切流程

Redis Cluster 解决分片和分片级高可用,不等于已经具备地域级灾难恢复;保存一份异地备份也不等于故障发生时应用能够自动切换。架构评审时需要分别描述每个目标,而不是笼统地写“Redis 已做高可用”。

1.2 用 RPO 和 RTO 描述故障目标

恢复点目标(Recovery Point Objective,RPO)表示故障后最多允许丢失多少数据,恢复时间目标(Recovery Time Objective,RTO)表示从故障发生到服务恢复最多允许多长时间。

对于光光平台,文章缓存可以接受较大的 RPO,因为缓存能够重建;登录会话可能允许丢失少量数据,但应限制受影响用户数量;邮件任务如果承担可靠业务通知,则需要更小的 RPO,并且必须有任务幂等和补偿机制。这些要求会直接影响复制、持久化、备份和业务隔离方式。

Redis Open Source 默认使用异步复制。Primary 已确认但尚未到达 Replica 的写入,在故障转移中仍可能丢失。WAIT 可以降低丢写概率,却不会把 Redis 变成强一致系统。因此 RPO 不能只写“有一个 Replica”,还要结合复制延迟、持久化策略和应用事实源一起判断。

1.3 建立统一的比较维度

选择架构前,至少应收集以下信息:

  • 数据集大小、增长速度、平均与峰值读写吞吐;
  • 最大可接受延迟和尾延迟,以及请求是否能够重试;
  • 单个 hot key、大 key、多 key 命令和 Lua 脚本的使用情况;
  • 能否接受陈旧读、重复执行或短时间不可用;
  • 节点、可用区和地域三个层级的 RPO、RTO;
  • 应用客户端是否支持 Sentinel 或 Redis Cluster;
  • 团队是否能够承担扩缩容、升级、备份和故障演练;
  • 缓存、会话、队列和控制状态之间允许多大的故障耦合。

只有当这些维度明确后,“自建还是托管”“直连还是代理”才有可验证的答案。否则复杂架构只是把未知风险从应用侧移动到了基础设施侧。

2. 部署形态与运维责任如何选择

自建 Redis Open Source 的优势是访问路径直接、配置可控,也没有服务商控制面的抽象层。团队可以根据负载选择 Standalone、Primary-Replica、Primary-Replica + Sentinel 或 Redis Cluster,并决定节点布局、持久化和升级窗口。

这种控制力的另一面,是生产责任没有消失。Redis 进程能够启动,只证明实例可以运行,并不证明系统已经具备高可用、可恢复和可持续运维能力。

如果选择托管服务,节点生命周期的一部分会交给服务控制面,但数据模型和应用正确性责任仍然留在业务团队。本章先说明部署形态与自建责任,再比较托管服务能够接管什么。

2.1 非分片还是分片:先判断单个 Primary 能否承载

如果完整数据集能够放入单个 Primary,而且单 Primary 写吞吐足够,就应先在非分片形态内选择恢复责任。数据完全可重建、可以接受人工恢复时,Standalone 最简单;需要 Replica 提供数据冗余或分担读请求,但由人工或外部控制面完成切换时,可以使用 Primary-Replica;需要 Redis Open Source 自动判断故障、提升 Replica 并让客户端发现新 Primary 时,则使用 Primary-Replica + Sentinel,并验证客户端支持 Sentinel。

在跨故障域部署时,一个 Primary、两个 Replica 和三个 Sentinel 是常见拓扑。Replica 提供数据冗余,Sentinel 负责故障判断、选举和服务发现。它保留了普通多 key 操作和事务的使用方式,运维复杂度也低于分片集群。

如果单个 Primary 已经成为内存或写吞吐瓶颈,则需要分片。自建 Redis Open Source 通常使用 Redis Cluster:多个 Primary 分担 16384 个哈希槽,每个分片再配置 Replica;Redis Software、Redis Cloud 或其他托管产品也可能通过服务端分片和 Proxy 提供不同的接入协议。分片扩展的是总容量和分散后的写入能力,但使用 Redis Open Source Cluster 或兼容 API 时,应用必须使用能够维护 slot 到节点映射并处理重定向的 Cluster-aware client,还要面对 hash tag、CROSSSLOT、hot slot 和 resharding 等问题。

因此,生产环境并不因为“重要”就天然需要 Cluster。数据量很小、跨 key 操作较多的系统使用 Cluster,可能只得到更高的节点成本和更复杂的故障路径。应该先证明单个 Primary 的容量或写吞吐已经成为约束,再承担分片代价。

2.2 高可用首先取决于故障域布局

下面两种部署在进程数量上相同,故障能力却完全不同:

错误布局:

一台主机
├── Primary
├── Replica 1
├── Replica 2
├── Sentinel 1
├── Sentinel 2
└── Sentinel 3

合理布局:

故障域 A:Primary   + Sentinel 1
故障域 B:Replica 1 + Sentinel 2
故障域 C:Replica 2 + Sentinel 3

第一种布局只能应对个别进程异常,主机故障会同时带走数据节点和 Sentinel 多数派。第二种布局才把相互依赖的角色分散到独立故障域。Cluster 也遵循相同原则:某个 Primary 与它唯一的 Replica 如果位于同一台主机或同一可用区,同一故障就可能让整个分片不可用。

故障域不仅是服务器。电源、交换机、机架、可用区、容器编排节点和共享存储都可能形成共同失效点。自建方案必须根据实际基础设施描述这些边界,不能仅凭逻辑拓扑判断冗余是否有效。

2.3 团队需要拥有完整运维闭环

自建 Redis 至少需要负责:

  • 节点安装、配置、补丁和版本升级;
  • CPU、内存、连接数、网络与磁盘容量规划;
  • 复制延迟、Primary-Replica 连接中断、故障转移和 Cluster 状态监控;
  • RDB、AOF、异地备份和恢复验证;
  • Sentinel 切换、Cluster 扩缩容与 slot 再平衡;
  • TLS、ACL、网络边界和凭据轮换;
  • 节点、可用区和依赖服务的故障演练;
  • 变更停止条件、回滚方案和事故响应流程。

尤其需要区分“有备份”和“能够恢复”。备份文件必须定期在隔离环境中验证能否加载,Cluster 则需要确认所有分片都有一致时间边界下的可用恢复材料。持久化、备份和恢复机制的详细边界见《Redis 持久化原理:RDB、AOF、数据恢复与生产实践》

2.4 托管服务接管什么,又没有接管什么

托管 Redis 通常可以接管实例创建、硬件故障处理、自动故障转移、补丁、监控入口、备份和部分扩缩容流程。对于没有专职 Redis 运维团队的项目,这些能力能够把大量低频但高风险的操作交给服务控制面。

不过“托管”并不代表应用可以忽略 Redis 语义。团队仍然需要负责:

  • 选择非分片或分片形态,确认客户端接入协议;
  • 设计 key、TTL、hash tag、淘汰策略和容量水位;
  • 处理超时、重试、重复执行和连接恢复;
  • 区分可重建缓存与不可随意丢失的数据;
  • 验证服务提供的 RPO、RTO、备份和跨地域能力是否满足业务;
  • 通过故障演练确认应用真的能够重连和降级。

托管服务的命令支持、模块、扩缩容方式、网络接入和故障语义并不完全相同。选型时应以所选产品当前的官方文档和实际演练为准,而不是把某个厂商的行为概括成所有“云 Redis”的共同能力。本文不比较厂商价格或服务级别协议(Service Level Agreement,SLA),因为这些信息变化较快,也不能替代业务侧的恢复验证。

3. 请求路由由谁负责:Cluster-aware client 还是 Proxy

分片之后,应用必须找到保存目标 key 的节点。Redis Open Source Cluster 把这项责任交给客户端;Redis Software 等产品还可以通过代理隐藏分片拓扑。托管服务可能暴露 Cluster 访问地址(endpoint)、代理访问地址或其他形式,因此是否托管并不直接决定请求路径;本章只比较客户端直连与代理转发这两种路由责任。

Redis Cluster client 直连与稳定 endpoint 加高可用 Proxy 的路由责任对比

3.1 Cluster-aware client 直接管理路由

图中左侧是 Redis Open Source Cluster 的典型请求路径:路由状态保存在应用使用的 Cluster client 中,请求不经过中心代理。

客户端启动时获取哈希槽与节点映射,随后根据 key 计算 slot,直接访问对应 Primary。拓扑变化时,客户端根据 MOVED 更新映射;传统 resharding 期间还要正确处理 ASKASKING。Redis 8.4+ 的 Atomic Slot Migration(ASM,原子哈希槽迁移)在快照和增量复制期间继续由源节点服务,但最终所有权交接时会短暂暂停源端写入;默认写暂停超时上限为 10 秒。团队仍需验证交接超时、重试和尾延迟,生产客户端也要兼容旧版本或传统迁槽工具。稳定状态下没有中心代理,少一次转发,也不存在单个代理承担全部数据流量的问题。

代价是复杂度进入了应用:客户端必须实现完整 Cluster 协议,连接池要同时维护多个节点,服务发现、TLS、拓扑刷新和连接风暴都需要验证。每种语言和客户端库的行为也可能不同。如果系统包含多种语言,团队需要分别验证它们在扩容、故障转移和地址变化时的表现。

3.2 Proxy 用稳定 endpoint 隐藏拓扑

图中右侧的代理式访问把请求路由从应用侧移动到基础设施侧。普通 Redis client 先连接稳定 endpoint,再由高可用 proxy 把请求转发到目标 shard。

应用只连接一个或一组稳定 endpoint,可以继续使用普通 Redis client,也不必直接感知节点迁移。对于语言栈较多、客户端能力不一致,或者希望集中管理 TLS、连接和路由的系统,这能明显降低接入复杂度。

但 Proxy 不是免费的抽象。请求多一次网络跳转,代理需要处理连接、带宽和每秒数据包;单个 Proxy 会形成新的性能瓶颈和故障点。因此生产代理层通常也需要多实例、负载均衡、健康检查和容量规划。

Proxy 隐藏拓扑,不代表所有产品都恢复成单实例命令语义。通用外置 Proxy 或后端启用 OSS Cluster API 时,跨 slot 多 key 约束通常仍然存在;Redis Software 专有分片模式可以跨 shards 执行 MGETMSETDEL 和 pipeline,但 MULTI/EXEC 事务、Lua 脚本及许多命令仍要求 keys 位于同一 slot。其中跨 shard 多 key 写能力不适用于 Active-Active:在 Active-Active 中,MGET 可以跨 slots 读取,而 MSETDELUNLINK 仍然是 single-slot 操作。具体边界取决于后端分片协议、数据库形态和命令,不能从“有 Proxy”一项推导;hot key 和大 key 也不会被代理自动拆开。

Redis Software 内置 proxy,并由数据库 endpoint 接收请求、转发到具体 shard。官方文档同时提供单 proxy、绑定各 Primary 所在节点以及绑定所有节点等策略;多个活动 proxy 可以提高吞吐和故障接管能力,也会增加资源消耗,并可能因为 proxy 与 shard 分布在不同节点而增加延迟。这属于 Redis Software 的产品能力,不能当作 Redis Open Source Cluster 内置了通用代理。

4. 单区域多可用区为什么是常见生产基线

大多数业务首先需要应对的不是整个地域消失,而是 Redis 进程、宿主机或一个可用区故障。将 Primary 和 Replica 分布到同一区域内的不同可用区,通常能在延迟、成本和故障覆盖之间取得较好的平衡。

4.1 多可用区保护的是区域内部故障

以三可用区的 Sentinel 拓扑为例,Primary、Replica 和 Sentinel 需要分散到不同故障域;某个可用区故障后,剩余 Sentinel 形成多数派并提升健康 Replica。

Redis 单区域三可用区的 Sentinel 故障转移基线

图中假设 AZ-A 整体失联,因此旧 Primary 对所有应用入口都不可达。若只是部分网络分区,Sentinel 多数派可以提升 B,但仍能访问 A 的少数侧客户端可能继续写入旧 Primary;Sentinel 本身不会替应用完成写入隔离。min-replicas-to-writemin-replicas-max-lag 或外部 fencing 可以限制分叉窗口,但不能保证零丢失。

分片集群需要让每个 Primary 的 Replica 位于不同可用区,避免一个可用区故障同时带走某个分片的所有 Replica。对于自建 Redis Open Source Cluster,仅分散每组 Primary 和 Replica 还不够;Primary shards 自身也应跨可用区分散,使预期保护的故障域丢失后仍有可达 Primary 多数,并为每个故障 Primary 保留可提升的 Replica。故障发生后,Sentinel、Redis Cluster 或托管控制面提升可用 Replica;应用再通过服务发现、Cluster 拓扑或稳定 endpoint 恢复连接。

Redis Cloud 的高可用文档把复制分为无复制、同可用区复制和多可用区复制。多可用区形态会把 Primary 与 Replica 放到不同可用区,以便整个可用区不可用时仍能故障转移。按照当前产品边界,免费的 Redis Cloud Essentials 不提供复制;多可用区需要付费 Essentials 或 Pro,并要求所选地域至少有三个可用区。启用复制后,内存需求约为数据集的两倍。复制与 Zone 设置的变更规则需要按套餐区分:Essentials 创建为 Multi-zone 后不能改为 Single-zone 或关闭复制,但 No Replication 与 Single-zone 可以随时互换;Pro 的 Zone 设置在订阅创建后不能修改,但每个数据库仍可随时启用或关闭复制。只有需要改变这些不可变的 Zone 设置时,才需要新建订阅并迁移数据。这里描述的是 Redis Cloud 的具体能力;自建 Redis Open Source 不会自动替团队完成可用区放置、地址切换和恢复验证。

4.2 自动切换不代表请求无感

一次可用区故障通常仍然包含以下时间窗口:

故障发生
  → 探测超时
  → 多数派确认
  → Replica 晋升
  → 拓扑或 endpoint 更新
  → 客户端断开旧连接
  → 建立新连接并恢复请求

在这段时间内,应用可能收到连接重置、超时或只读节点错误。客户端必须设置有边界的退避与重试,业务操作还需要考虑幂等。对于 INCR、任务入队等操作,连接中断时客户端可能无法确定命令是否已经执行,盲目重试会造成重复结果。

多可用区也没有改变异步复制的基本事实。刚刚写入 Primary、尚未到达被提升 Replica 的数据仍可能丢失。因此它主要改善区域内 RTO 和故障覆盖,并不自动提供 RPO 为零的强一致保证。

4.3 多可用区不等于跨地域灾备

同一区域的多个可用区仍然可能共享区域级控制面、网络入口或上游依赖。区域整体不可用、错误数据同步到全部 Replica、凭据或配置同时失效时,区域内 Replica 可能无法提供恢复路径。

所以光光平台可以把多可用区作为文章缓存和 Session Redis 的常见生产基线,但如果业务明确要求地域级连续性,还需要独立设计跨地域数据复制、应用流量切换、回切和数据校验。它们不是多添加一个 Replica 就能自然获得的能力。

5. Active-Passive 如何完成跨地域灾备

Active-Passive 指正常情况下只有主地域承担写入,灾备地域保存异步副本、快照或预置集群,等待主地域不可用时接管。这种模式避免了多地域并发写冲突,是更容易理解和控制的跨地域方案。

Redis Open Source 可以跨网络建立复制链路,也可以使用备份在远端重建数据,但它不会因此自动获得一套完整的地域级 Active-Passive 控制面。旧主隔离、灾备提升、应用切流、数据校验与恢复回切,仍然需要外部基础设施和运维流程完成。

5.1 正常复制、故障切流与恢复回切

一条完整链路至少包含三个阶段:

  1. 正常阶段:用户请求进入主地域应用和 Redis,数据通过异步复制或备份进入灾备地域。
  2. 故障切换:停止或隔离旧写入口,检查灾备数据的新鲜度与完整性,解除目标端复制或只读关系,提升灾备数据库并开放写入,最后把全局流量切向灾备地域。
  3. 恢复回切:主地域恢复后,先重新建立一致的数据基线,再反向同步或重建主地域,最后灰度切回流量。

Redis Active-Passive 从正常复制、故障切换到恢复回切的完整生命周期

真正困难的通常不是“远端有一份数据”,而是如何防止两个地域同时接受互不兼容的写入,以及恢复后以哪一侧数据为准。

建立复制链路本身也可能删除目标端数据。Redis Software 将数据库定义为 Replica Of 目标时,会删除目标数据库的已有数据并用源端数据替换;Redis Cloud Pro 目标数据库启用 Active-Passive 时则会 flush 目标数据库。因此目标端应使用专用空库,或者先确认其中没有重要数据;如果必须复用已有数据库,应先完成备份并对清空操作进行明确确认。

Redis Software 把这项异地复制能力称为 Replica Of,目标数据库接收写请求前必须先解除 Replica Of 关系,否则后续全量同步可能覆盖灾备端的新写入。Redis Cloud 把对应形态称为 Active-Passive,其目标数据库需要位于 Redis Cloud Pro,源端可以来自 Redis Cloud Pro、Redis Cloud Essentials 或外部 Redis。如果源、目标都是 Redis Cloud 数据库,直接配置 Active-Passive 时需要位于同一 Redis Cloud 账号;跨账号迁移需要先联系 Redis 支持,不能把“外部 Redis”入口视为通用的跨账号绕过方式。

计划切换时,应先停止源端写入,等待目标端达到 Synced,再关闭 Active-Passive 并切换连接;非计划灾难中,源端可能已经不可达,无法继续等待追平,此时要先隔离旧写入口,检查目标端最后复制位置并接受对应 RPO,再关闭 Active-Passive、开放目标端写入。启用 Active-Passive 时直接写目标端,可能造成数据不一致和复制失败。

只要 Replica Of 或 Active-Passive 仍然启用,目标数据库就不会独立执行 key 过期和淘汰,而是依赖源端传播的数据变化。灾备端不能把本地 TTL 或淘汰策略当作容量保护,应为完整同步数据及复制波动预留内存,并在切换演练中验证解除复制关系后的 TTL、淘汰和容量表现。

Redis Open Source 则需要显式提升 Replica,并由外部流程完成旧写入口隔离。无论使用哪种产品,切换前都要有明确的写入隔离(fencing)措施;回切前则要确认原主地域不会带着旧状态重新加入并覆盖新数据。

5.2 复制延迟决定实际 RPO

跨地域网络的往返延迟、带宽和抖动通常高于区域内复制。异步复制能够避免每次写入都等待远端,却意味着灾备地域总可能落后。主地域突然丢失时,实际 RPO 由灾备端已经接收和持久化到什么位置决定,而不是由“跨地域复制已开启”这句话决定。

对于文章缓存,这个窗口通常可以接受,因为数据库仍是事实源;对于 Session,它可能表现为部分用户重新登录;对于邮件任务,则可能造成任务遗漏或重复,需要业务记录、幂等键和补偿扫描共同处理。越依赖 Redis 保存不可重建状态,越需要把复制延迟和恢复校验纳入监控。

5.3 灾备方案必须包含应用流量

数据库已经在灾备地域可写,应用也不一定能够立即恢复。DNS 缓存、负载均衡健康检查、网络访问控制、TLS 证书、密钥、配置中心和下游数据库都可能阻塞切流。

因此 Active-Passive 的 RTO 是以下过程之和,而不只是 Redis Replica 晋升时间:

故障确认
+ 数据新鲜度判断
+ 数据库提升
+ 应用和网络切流
+ 客户端重连
+ 业务验证

灾备操作手册(runbook)还必须覆盖恢复回切(failback)。只有定期演练“切过去”和“切回来”,并验证数据差异、连接恢复和业务降级,才能把异地副本转化为真实的灾难恢复能力。

6. Active-Active 如何允许多个地域同时写

Active-Passive 在远离主地域的用户请求上通常仍需要跨地域访问,或者只允许读取本地 Replica。如果多个地域都必须以本地延迟读写同一数据集,就进入了 Active-Active 的范围。

6.1 多 Primary 写入为什么需要冲突语义

假设上海和法兰克福同时修改同一个计数器:

上海:    INCR article:8848:view-count
法兰克福:INCR article:8848:view-count

网络分区期间,两边都不能立即看到对方的操作。恢复连接后,如果系统只保留最后到达的值,其中一次增长就可能消失。字符串覆盖、集合增删、计数器累加和列表操作需要的合并规则也不相同,不能用同一种“最后写入获胜”规则准确表达所有意图。

冲突自由复制数据类型(Conflict-free Replicated Data Type,CRDT)把合并规则编码进数据类型,使多个副本在分别接受更新后,能够在收到相同操作集合时收敛到一致结果。它解决的是并发更新如何确定性合并,不是让跨地域操作瞬间同步。

Redis Active-Active 在网络分区期间临时分歧并通过 CRDT 最终收敛

6.2 最终一致性的业务边界

Redis Active-Active 使用强最终一致性模型:网络正常并且更新完成传播后,各地域最终收敛;传播完成前,各地读到的值可以不同。即使冲突能够自动解决,应用仍要理解短时间不一致和跨 key 业务约束。

这类架构适合:

  • 全球用户需要在就近地域更新偏好、购物车或非关键状态;
  • 计数、集合等操作可以按照对应 CRDT 语义合并;
  • 业务能够接受跨地域短时间读取不同值;
  • 地域间网络中断时仍希望每个地域继续写入。

它不应在没有额外正确性设计的情况下承担余额、账本、全局唯一库存扣减、全局锁或要求严格顺序的任务队列。CRDT 可以解决定义范围内的冲突合并,却不会自动满足跨多个 key 的事务不变量。

Active-Active 还会改变容量和淘汰边界。每个参与地域不仅要容纳数据集,还要为 CRDT 元数据和跨地域 Active-Active backlog 预留内存;区域内数据库复制还会引入 Replica 和数据库复制 backlog。Redis Software 官方文档指出,这些开销可能让数据库所需内存增加到两倍或更多。Redis Cloud Active-Active 本身要求启用区域内数据库复制:Primary 与 Replica 先使内存需求达到约两倍,Active-Active 复制再叠加一层,内存上限影响最高可能达到原始数据集的四倍。这些数字是产品容量规划边界,不是可以套用到所有部署的固定公式,选型时仍应按具体数据类型、写入速率和产品配置重新估算。

6.3 Redis Software、Redis Cloud 与 Open Source 的能力边界

Redis 官方提供的 CRDT Active-Active 是 Redis Software 和 Redis Cloud 的产品能力:Redis Software 可以自主管理企业级集群;Redis Cloud Active-Active 则需要使用支持该能力的 Redis Cloud Pro 订阅。Redis Software 把同一数据库部署到至少两个参与集群;Redis Cloud 在多个地域建立可读写的数据库副本。两种形态都会在地域间进行多 Primary 复制和冲突解决。

Redis Open Source 的 Sentinel 和 Redis Cluster 不提供同等的跨地域 CRDT Active-Active:Sentinel 维护单个逻辑 Primary,Cluster 虽然有多个 Primary,但每个 hash slot 在稳定状态下仍由一个 Primary 负责写入。不能把“Cluster 有多个 Primary”理解为“同一份 key 可以在多个地域同时写”。

即使使用 Redis Software 或 Redis Cloud Active-Active,应用连接的跨地域 failover 和 failback 也不是自动消失的。Redis 官方文档明确要求应用通过全局流量管理、代理、支持故障转移的客户端或应用逻辑,把请求从不可用地域切到远端数据库。因此还要独立设计 endpoint 健康检查、流量切换和恢复后的回切策略。

连接切到远端实例也不代表 RPO 为零。Active-Active 复制和区域内 Primary-Replica 复制都是异步的;远端 endpoint 可能尚未收到本地已经确认的写入。若原地域只是暂时故障,这些写入可能在恢复后继续收敛;若本地持久化文件同时丢失,它们也可能永久丢失。因此 Active-Active 仍需要持久化、备份、复制延迟监控和业务补偿。

Active-Active 的淘汰策略也会比普通数据库更早介入:当任一实例达到内存上限的 80% 时,Redis Software 和 Redis Cloud 就会开始执行配置的淘汰策略,为跨地域传播预留空间。Redis Software 官方规划文档还特别提醒,如果数据库使用 noeviction,同时又没有能够过期的 key,OOM 可能让跨地域复制持续失败并造成实例失同步。在 Redis Software 中,运行 Redis 8.4 及以上版本的 Active-Active 数据库可以通过复制 OOM 缓冲区为内部复制保留内存,但它不能替代容量水位、backlog 和复制状态监控。

7. 为什么缓存、会话、队列和控制状态需要隔离

选择完节点拓扑后,还需要决定不同业务是否共用一套 Redis。命名空间隔离能够避免 key 重名,却不能隔离 CPU、内存、淘汰、持久化、延迟尖峰和节点故障。生产事故中,真正危险的往往不是 key 名冲突,而是一个业务耗尽资源后拖垮所有 Redis 用途。

7.1 四类负载有不同的故障语义

用途 数据能否淘汰 常见持久化要求 主要故障影响
Cache 通常可以 较低,数据可从事实源重建 命中率下降、数据库压力上升
Session 通常不应随意淘汰 取决于能否接受用户重新登录 用户掉线、登录状态回退
Queue / Stream 不应淘汰未处理数据 通常较高,并需要任务补偿 任务丢失、重复或积压
Control 不应意外淘汰 取决于限流、幂等和锁的正确性要求 重复执行、并发冲突、保护失效

缓存 Redis 通常允许 allkeys-lruallkeys-lfu 淘汰低价值数据,并通过 TTL 控制生命周期。Session、Queue 和控制状态则更常选择 noeviction,在容量不足时显式失败和告警,而不是静默删除仍有业务意义的 key。

Redis 官方淘汰策略文档也指出:如果一个实例同时保存可淘汰缓存和需要保留的 key,即使可以使用只淘汰带过期时间 key 的策略,条件允许时仍应考虑拆为两个实例。原因不仅是策略更清晰,也包括容量和故障影响能够独立管理。

7.2 Queue 和控制状态还需要业务正确性

把 Queue 单独部署并启用 AOF,不代表任务处理正好一次。消费者可能在任务已经完成、确认消息尚未成功时崩溃,故障切换也可能造成重复读取或状态回退。任务执行必须具备幂等键、重试上限、死信或补偿扫描,并为积压量和最老任务年龄设置告警。

分布式锁和幂等控制也不能只依赖一个 Redis key 承担最终正确性。异步复制切换后,锁或幂等键可能丢失;锁持有者还可能在长时间暂停后继续写入。余额、订单唯一性等约束应由事务数据库唯一索引、状态机或单调递增的隔离令牌(fencing token)等机制兜底;使用隔离令牌时,资源端必须拒绝比当前版本更旧的令牌。Redis 更适合作为快速协调层,而不是不可推翻的事实来源。

限流的要求则取决于失败策略:面向普通页面的限流可以在 Redis 不可用时暂时放行(fail-open),保护昂贵下游接口的限流可能需要在失败时拒绝请求(fail-closed)。两者即使使用相同算法,也不一定适合共享故障策略。

7.3 从命名隔离逐步升级到故障域隔离

常见隔离方式可以分为五级:

隔离方式 能隔离什么 不能隔离什么
Key prefix 命名空间 CPU、内存、淘汰、持久化、故障
ACL / User 访问权限和命令范围 资源争用与实例故障
逻辑数据库 Key 视图 进程、内存、淘汰和故障;Cluster 只支持 DB 0
独立实例 内存上限、淘汰、持久化和发布节奏 共享宿主机或可用区故障
独立高可用集群 资源、配置和发布节奏;可以独立规划故障域 若仍共享宿主机、可用区、网络或控制面,基础设施故障仍会共同影响

拆分不应机械地采用“一项功能一个 Redis”。更合理的标准是数据价值、资源曲线和故障策略是否一致。如果两个缓存具有相似 TTL、可以共同降级并且负载平稳,可以共享实例;如果邮件任务不能被淘汰,而文章缓存会持续挤占内存,就应该至少拆成独立实例。业务隔离的目标是限制故障半径,而不是让架构图拥有更多方框。

对于光光平台,可以将文章缓存、登录会话、邮件任务和控制状态按各自的数据价值、资源曲线和故障策略逐步拆分,并为它们独立规划容量与故障域:

Redis 从共享实例到缓存、会话、队列和控制状态边界拆分的演进

项目早期可以先进行逻辑分类和监控,达到容量、淘汰或故障语义边界时再物理拆分。独立 Redis 若仍共用宿主机、可用区或控制面,只形成了工作负载边界,不等于已经隔离基础设施故障;节点放置仍需按第 2.2 节的故障域原则设计。这样既避免过早建设四套小集群,也保留了清晰的演进路径。

8. 如何把业务需求转换成最终拓扑

Redis 生产架构没有脱离业务约束的标准答案。一个可复用的决策顺序,是先决定是否分片,再决定区域内高可用、跨地域恢复和业务隔离,最后分别确定由 Cluster-aware client 还是 Proxy 承担请求路由,以及由团队自建还是托管服务承担基础设施生命周期。

8.1 一棵从单节点到跨地域的决策树

完整数据集和峰值写吞吐能否由一个 Primary 承载,是决策树的第一个分叉。但在把“不能承载”翻译为分片前,应先确认瓶颈不是单个 hot key、big key 或无法拆分的单请求:Cluster 只能把不同 keys 分散到多个 shards,不能自动拆开一个 key 或针对它的集中访问。只有负载能够按独立 keys 分散时,分片才能扩大总容量和分散写入。此后再分别判断区域内故障转移、分片路由、地域级恢复、工作负载隔离和运维责任。

接入能力也必须按实际协议验证。非分片自动切换需要支持 Sentinel 服务发现的 client,或者由托管控制面或 Proxy 提供真正随 Primary 变化的稳定 HA endpoint;固定节点地址不具备这一能力。分片时,普通 Redis client 只有连接到真正隐藏 MOVEDASK 和拓扑变化的高可用 Proxy 或 HA endpoint 才能工作;如果 endpoint 暴露 Redis Cluster 协议,仍然需要 Cluster-aware client,不能把所有托管 endpoint 泛化为代理式接入。

从业务容量、高可用、客户端能力和地域目标选择最终 Redis 拓扑的决策树

决策树中的每一步都应由数据支持。例如,“需要分片”应有单机内存、峰值吞吐或增长预测证据;“需要 Active-Active”应有多地域同时写和本地延迟目标,而不只是希望架构更先进。

8.2 光光平台的一个渐进式选择

对于本文虚构的光光平台,可以得到如下方案:

  • 文章缓存:优先使用单区域多可用区的非分片高可用 Redis;只有容量或分散写入达到单 Primary 边界时才升级为分片形态,再根据客户端能力和运维责任选择 Redis Open Source Cluster 或托管分片。跨地域时,各地域可以分别从 PostgreSQL 或内容源构建本地缓存,通常没有必要同步全部缓存写入。
  • 登录会话:使用独立高可用 Redis,根据用户能否接受重新登录决定 AOF、跨地域副本和 RPO。多地域同时修改同一 Session 前,需要先定义冲突语义。
  • 邮件任务:使用独立 noeviction 实例,配置复制与持久化,并由数据库任务记录、消费者幂等和补偿扫描保证最终完成;如果可靠性要求超出 Redis 队列边界,应评估专门的消息系统。
  • 限流与幂等:可以共享控制类 Redis,但要按接口选择 fail-open 或 fail-closed;订单唯一性等最终约束仍由 PostgreSQL 保证。
  • 业务事实源:文章、用户、订单和任务最终状态继续保存在 PostgreSQL,Redis 负责缓存、短期状态和加速,不承担无法重建的唯一事实。

如果团队没有成熟的 Redis 值班、扩缩容和恢复能力,托管多可用区 Redis 通常比自建复杂拓扑更容易形成完整闭环;如果对访问路径、部署环境和配置有强控制要求,并且团队能够承担故障演练,自建 Redis Open Source 也可以是合理选择。二者的区别不是“专业”与“不专业”,而是运维责任由谁持有。

8.3 本文的八个结论

综合来看,Redis 架构选型可以归纳为以下结论:

  1. Sentinel 解决非分片 Primary 的自动接管,Redis Cluster 解决分片和分片级高可用,两者不是同一规模下的替代品。
  2. 高可用、横向扩展和灾难恢复是三个独立目标,需要分别描述故障域、RPO 和 RTO。
  3. Cluster-aware client 用应用复杂度换取直接访问路径;proxy 用基础设施复杂度换取稳定 endpoint。
  4. 托管服务可以接管大量基础设施操作,但不会替应用设计 key、重试、幂等和降级。
  5. 单区域多可用区是常见生产基线,跨地域 Active-Passive 还需要切流和回切流程。
  6. CRDT Active-Active 属于 Redis Software 和 Redis Cloud 能力,提供多地域写与最终收敛,不等于强一致;选型时还要接受额外的复制、CRDT 元数据与 backlog 容量开销,以及更早介入的淘汰阈值。它不消除异步复制的 RPO 边界。
  7. 缓存、会话、队列和控制状态应根据淘汰、持久化与故障语义决定是否拆分,而不是只靠 key prefix 共用一切。
  8. 对不能接受已确认写入丢失的最终业务状态,应保留具备相应事务和持久性保证的事实源。

参考资料