跳转至

Redis 集群模式与选型

30 秒版(开场)

Redis 部署分 单机、主从、Sentinel、Cluster 四档:读多写少用主从+Sentinel 保 HA;数据量/吞吐超单机用 Cluster 16384 slot 分片。Go 侧用 go-redis,Cluster 客户端需感知 MOVED/ASK 重定向。生产关键词:slot 迁移、脑裂、连接池、Pipeline 跨 slot 限制。

3 分钟版(精讲深度)

  1. 是什么:Redis 提供多种拓扑——主从复制同步数据,Sentinel 监控主节点故障并自动 failover,Cluster 将 key 按 CRC16 mod 16384 映射到 slot 再分配到节点。
  2. 为什么:单机有内存与 QPS 上限;主从解决读扩展但不自动切主;Sentinel 补 HA;Cluster 同时解决水平扩展与高可用(每个 master 可挂 slave)。
  3. 怎么做:数据和写吞吐能由单主承载时可选 Sentinel;需要分片容量/写吞吐时选 Cluster。容量阈值必须压测。Hash Tag 让多 key 落同 slot,从而可执行 Lua/MULTI,但不把 Redis 异步复制变成故障下的线性一致存储。

10 分钟版(原理 + 图示)

模式对比

模式 扩展 HA 复杂度 典型场景
单机 否 否 低 开发/小缓存
主从 读扩展 手动切主 低 读多写少
Sentinel 读扩展 自动 failover 中 中小生产
Cluster 读写扩展 分片+副本 高 大数据量/高 QPS
flowchart TB
  subgraph cluster[Redis Cluster 方案]
    Client[go-redis ClusterClient] --> Router{slot 路由}
    Router -->|MOVED/ASK| NodeA[Master A slot 0-5460]
    Router --> NodeB[Master B slot 5461-10922]
    NodeA --> ReplicaA[Replica A]
    NodeB --> ReplicaB[Replica B]
  end
  subgraph sentinel[Sentinel 方案(非 Cluster 组件)]
    App2[普通 Redis Client] --> Primary[Single Primary]
    Primary --> Replica[Replica]
    Sentinels[Sentinel quorum] -.->|监控与 failover| Primary
  end

Cluster 要点:Gossip 传播拓扑;CLUSTER NODES 看 slot 分布;扩缩容时 slot migrate 产生 ASK;服务端多 key 命令与事务通常要求同 slot。Sentinel 的 quorum 用于客观下线判断,真正授权 failover 还需多数 Sentinel;min-replicas-to-write 只能降低分区时继续写旧主的风险,不能保证零丢写。

Go 客户端:redis.NewClusterClient 维护 slot→node 缓存;Cluster pipeline 可由客户端按节点拆批,但跨 slot 的事务和原子多 key 操作仍受限制。

生产场景

  • 缓存层 50GB+:单机 OOM → 迁 Cluster,按业务 prefix 设计 key 避免 big key 单 slot 热点。
  • 秒杀库存:单 key 热点 → 本地缓存 + Redis 分片 key(stock:{sku}:0..N)而非强上 Cluster。
  • 跨 AZ 部署:Cluster 跨机房 RTT 放大,考虑同城双活 + Proxy(Codis/Twemproxy 已过时,现多用 Cluster 原生或 Redis Enterprise)。

排查与工具

工具 用途
redis-cli --cluster check slot 覆盖、迁移状态
INFO replication 主从 lag、连接数
redis-cli --latency 网络/慢命令
SLOWLOG GET 热 key、大 value
Prometheus redis_exporter 内存、命中率、evicted

路径:超时飙升 → 看是否 MOVED 风暴(拓扑变更)→ CLIENT LIST 连接数 → 慢日志定位大 key / KEYS *。

架构取舍

方案 适用 不适用
Sentinel + 主从 <32GB,团队运维能力一般 需水平写扩展
Redis Cluster 大数据量、可接受 slot 规划 强跨 slot 多 key 原子
托管 Redis(云) 快速上线、免运维 成本敏感、定制协议
本地缓存 + Redis 极热读 一致性要求高

深挖问答

  1. Cluster 如何算 slot? → CRC16(key) mod 16384;Hash Tag 只对 {} 内部分哈希。
  2. MOVED 和 ASK 区别? → MOVED 永久迁移完成;ASK 临时重定向,迁移窗口内。
  3. Sentinel 脑裂怎么办? → Sentinel 和 Redis 副本跨故障域部署、使用多数派并设置 min-replicas-to-write 等保护;旧主恢复后应被重配置为 replica,但网络分区窗口仍可能有已确认写丢失。
  4. go-redis 连接池参数? → PoolSize、MinIdleConns、ReadTimeout;Cluster 每节点独立池。
  5. RDB 还是 AOF? → 缓存可 RDB+短 AOF;持久化队列倾向 AOF everysec。

反模式与事故

  • 生产 KEYS * 或 FLUSHALL 无 alias 保护——曾致全站缓存穿透 DB。
  • Cluster 下用 MULTI 跨 slot——直接报错或逻辑错误。
  • Sentinel quorum=1 或两节点「伪 HA」——网络分区双主写。
  • 不设 maxmemory-policy,OOM 后写拒绝或随机 evict 打穿 DB。

代码示例

import "github.com/redis/go-redis/v9"

func newCluster() *redis.ClusterClient {
    return redis.NewClusterClient(&redis.ClusterOptions{
        Addrs:        []string{"10.0.0.1:6379", "10.0.0.2:6379"},
        PoolSize:     100,
        MinIdleConns: 10,
        ReadTimeout:  200 * time.Millisecond,
    })
}

// Hash Tag:profile 与 orders 同 slot
const userProfileKey = "{user:42}:profile"
const userOrdersKey  = "{user:42}:orders"

延伸阅读