Redis 高可用:从主从复制到集群架构的演进之路

4 阅读9分钟

Redis 高可用:从主从复制到集群架构的演进之路

本文将从零开始,带你全面理解 Redis 高可用架构的演进历程,包括主从复制、哨兵模式、集群架构,以及生产环境中的最佳实践。


一、为什么需要高可用?

1.1 单机 Redis 的问题

Redis 作为高性能的键值存储系统,在单机模式下存在明显的瓶颈:

问题描述影响
单点故障节点宕机后服务完全不可用业务中断,用户体验受损
容量限制受限于单机内存(通常 ≤ 64GB)无法存储海量数据
性能瓶颈读写能力受限于单核 CPU无法应对高并发场景
维护困难停机维护期间服务不可用无法做到无感知升级

1.2 高可用演进路线

单机 → 主从复制 → 哨兵模式 → 集群架构
  │        │          │          │
  ▼        ▼          ▼          ▼
 备份    读写分离   自动故障转移   水平扩展

二、主从复制:数据冗余的起点

2.1 什么是主从复制?

主从复制是指将主节点的数据同步到从节点,实现数据的冗余备份。

┌─────────────────────────────────────────────────────────────────────┐
│                        主从复制架构                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   写请求 ──▶ 主节点 ──▶ 从节点1(只读)                            │
│                │                                                   │
│                └──────▶ 从节点2(只读)                            │
│                                                                     │
│   特点:                                                           │
│   • 主节点可读写,从节点只读                                        │
│   • 数据自动从主同步到从                                            │
│   • 支持一主多从,从节点可以再有从节点                              │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.2 核心原理

主从复制分为两个阶段:

全量同步(首次连接):

  1. 从节点发送 PSYNC 命令请求同步
  2. 主节点 fork 子进程生成 RDB 快照
  3. 主节点将 RDB 文件发送给从节点
  4. 从节点清空旧数据,加载 RDB
  5. 主节点将期间的写命令发送给从节点

增量同步(正常运行):

  • 主节点每执行一条写命令,就发送给从节点
  • 从节点执行相同的命令,保持数据一致

关键概念:

  • 复制偏移量:标记已同步的数据位置
  • 复制积压缓冲区:存储最近的写命令,用于断线重连后的增量同步

2.3 优缺点分析

优点缺点
✅ 数据冗余备份❌ 主节点宕机需人工介入
✅ 读写分离,分担读压力❌ 写操作仍在单节点
✅ 实现简单❌ 无法自动故障转移
✅ 从节点可做离线分析❌ 数据容量受限于主节点内存

2.4 快速搭建

# 启动主节点
redis-server --port 6379

# 启动从节点
redis-server --port 6380 --slaveof 127.0.0.1 6379
redis-server --port 6381 --slaveof 127.0.0.1 6379

# 查看复制状态
redis-cli INFO replication

三、哨兵模式:自动故障转移

3.1 什么是哨兵?

哨兵(Sentinel)是 Redis 官方提供的高可用解决方案,它可以监控主从节点,并在主节点故障时自动完成故障转移。

┌─────────────────────────────────────────────────────────────────────┐
│                        哨兵模式架构                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐                           │
│   │ 哨兵1   │  │ 哨兵2   │  │ 哨兵3   │  ← 监控集群                │
│   └────┬────┘  └────┬────┘  └────┬────┘                           │
│        │            │            │                                 │
│        └────────────┼────────────┘                                 │
│                     ▼                                               │
│              ┌──────────┐                                          │
│              │  主节点   │                                          │
│              └────┬─────┘                                          │
│                   │                                                 │
│            ┌──────┴──────┐                                         │
│            ▼             ▼                                         │
│         ┌──────┐      ┌──────┐                                    │
│         │从节点│      │从节点│                                    │
│         └──────┘      └──────┘                                    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3.2 三大职责

职责说明
监控定时检查主从节点是否存活
选主主节点下线后,选举新主节点
通知通知客户端新主节点地址

3.3 下线判断机制

  • 主观下线:单个哨兵认为主节点下线(SDOWN)
  • 客观下线:超过法定人数(quorum)的哨兵都认为主节点下线(ODOWN)

3.4 选主算法

哨兵选择新主节点的优先级:

  1. 排除下线和断连过久的从节点
  2. slave-priority 配置排序(数字越小越优先)
  3. 优先级相同,比较复制偏移量(数据越新越优先)
  4. 偏移量相同,比较 runid(字典序越小越优先)

3.5 配置文件示例

# sentinel.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

3.6 优缺点分析

优点缺点
✅ 自动故障转移❌ 故障转移期间写操作不可用
✅ 无需人工介入❌ 配置相对复杂
✅ 支持多哨兵防止误判❌ 数据容量仍受单机限制

四、集群架构:水平扩展的终极方案

4.1 什么是 Redis Cluster?

Redis Cluster 是 Redis 的分布式解决方案,通过分片(Sharding)将数据分散到多个节点,实现水平扩展。

4.2 核心概念:哈希槽

Redis Cluster 将整个数据空间划分为 16384 个哈希槽

slot = CRC16(key) % 16384
┌─────────────────────────────────────────────────────────────────────┐
                        哈希槽分布                                    
├─────────────────────────────────────────────────────────────────────┤
                                                                     
   节点1                节点2                节点3                   
   ┌─────────┐          ┌─────────┐          ┌─────────┐            
    0~5460            │5461~10922│         │10923~16383│          
    5461个槽            5462个槽            5461个槽           
   └─────────┘          └─────────┘          └─────────┘            
                                                                     
   每个节点知道自己负责哪些槽,也知道其他节点负责哪些槽                
                                                                     
└─────────────────────────────────────────────────────────────────────┘

4.3 客户端定位数据流程

客户端请求 "user:1001"
        │
        ▼
计算 slot = CRC16("user:1001") % 16384 = 5230
        │
        ▼
查槽表:slot 5230 → 节点1
        │
        ▼
发送请求到节点1
        │
        ▼
节点1 检查自己是否负责该槽?
   ├── 是 → 直接返回数据
   └── 否 → 返回 MOVED 重定向

4.4 节点通信:Gossip 协议

集群节点之间通过 Gossip 协议通信,每个节点定期随机与其他节点交换信息:

消息类型作用
PING检测节点是否存活
PONG响应 PING,或主动广播状态
MEET新节点加入集群
FAIL广播节点下线

4.5 集群搭建(Docker Compose)

# docker-compose.yml
version: '3.8'

services:
  redis-node-1:
    image: redis:7
    command: redis-server --port 6379 --cluster-enabled yes
    ports:
      - "7001:6379"

  redis-node-2:
    image: redis:7
    command: redis-server --port 6379 --cluster-enabled yes
    ports:
      - "7002:6379"

  redis-node-3:
    image: redis:7
    command: redis-server --port 6379 --cluster-enabled yes
    ports:
      - "7003:6379"

  # 初始化集群
  cluster-init:
    image: redis:7
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
    command: >
      sh -c "echo 'yes' | redis-cli --cluster create
      redis-node-1:6379 redis-node-2:6379 redis-node-3:6379
      --cluster-replicas 0"

4.6 集群操作命令

# 创建集群
redis-cli --cluster create 192.168.1.1:6379 192.168.1.2:6379 192.168.1.3:6379

# 查看集群节点
redis-cli CLUSTER NODES

# 查看集群信息
redis-cli CLUSTER INFO

# 查看槽分配
redis-cli CLUSTER SLOTS

# 添加节点
redis-cli --cluster add-node new_host:new_port existing_host:existing_port

# 重新分配槽
redis-cli --cluster reshard host:port

4.7 优缺点分析

优点缺点
✅ 水平扩展,容量无限❌ 实现复杂,运维成本高
✅ 高吞吐,写性能随节点线性提升❌ 客户端需支持集群协议
✅ 自动故障转移❌ 多 key 操作受限
✅ 无中心化架构❌ 批量操作需要同一槽

五、三种架构对比

对比维度主从复制哨兵模式集群架构
数据容量受限于单机受限于单机可水平扩展
写性能受限于单机受限于单机随节点线性增长
读性能可增加从节点可增加从节点随节点线性增长
故障转移手动自动自动
客户端复杂度
运维复杂度
适用场景数据量 < 50GB数据量 < 50GB大数据量、高吞吐

六、生产环境最佳实践

6.1 架构选型建议

场景推荐架构理由
数据量 < 50GB,可接受短暂停机主从复制简单够用
数据量 < 50GB,需要高可用哨兵模式(1主2从+3哨兵)自动故障转移
数据量 > 50GB,或高吞吐要求集群架构(3主3从起)水平扩展
云原生环境集群架构弹性伸缩

6.2 配置推荐

# 通用配置
maxmemory 16gb
maxmemory-policy allkeys-lru

# 主从配置(从节点)
replica-read-only yes
replica-serve-stale-data yes

# 哨兵配置
sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000

# 集群配置
cluster-enabled yes
cluster-node-timeout 15000
cluster-migration-barrier 1

6.3 监控指标

指标说明告警阈值
connected_slaves连接的从节点数< 配置值
master_repl_offset主节点复制偏移量关注变化
cluster_state集群状态不为 ok
cluster_slots_assigned已分配槽数< 16384

七、常见面试题

Q1: 主从复制的全量同步和增量同步分别在什么情况下触发?

全量同步:

  • 从节点第一次连接主节点
  • 从节点断线重连,但 offset 不在 backlog 范围内
  • 主节点 runid 不匹配

增量同步:

  • 从节点断线重连,offset 仍在 backlog 范围内
  • 正常运行期间持续进行

Q2: 哨兵模式下,为什么需要奇数个哨兵?

为了投票。3 个哨兵最多投 2 票,4 个哨兵也可能只投 2 票。奇数个哨兵更容易达成共识,避免脑裂问题。

Q3: 为什么 Redis Cluster 是 16384 个槽?

  • 心跳包中需要携带槽信息,16384 个槽的位图只有 2KB
  • 集群规模建议不超过 1000 个节点,16384 足够分配
  • 在空间和灵活性之间取得平衡

Q4: 集群模式下,如何支持多 key 操作?

使用 hash tag:{user:1001}:name{user:1001}:age 会被分配到同一个槽。只有同一槽内的多个 key 才能进行批量操作。


八、总结

从单机到主从、从主从到哨兵、从哨兵到集群,Redis 的高可用架构经历了三个重要阶段:

  1. 主从复制:解决了数据备份和读写分离的问题,但无法自动故障转移
  2. 哨兵模式:在主从复制的基础上实现了自动故障转移,但数据容量仍受单机限制
  3. 集群架构:通过分片实现了水平扩展,支持海量数据和高吞吐场景

在实际生产中,应根据业务需求选择合适的架构:

  • 小规模应用(< 50GB):哨兵模式足够
  • 大规模应用(> 50GB):必须使用集群架构
  • 追求极致性能:可考虑读写分离 + 本地缓存组合

参考资料


本文是 Redis 学习系列的一部分,后续会继续分享缓存三大问题、大 Key 排查治理等实战内容,欢迎关注交流。