Redis 集群方案详解:主从复制、哨兵与 Cluster

Redis 集群方案详解:主从复制、哨兵与 Cluster

admin
2026-07-24 / 0 评论 / 1 阅读

前言

当单机 Redis 无法满足业务需求时,就需要引入集群方案。Redis 提供了三种主要的集群模式:主从复制、哨兵模式和 Cluster 集群。本文将系统讲解三种方案的原理、搭建和适用场景。

一、主从复制

1.1 架构

           ┌──────────────┐
           │   Master     │
           │  (读+写)     │
           └──────┬───────┘
                  │ 复制
       ┌──────────┼──────────┐
       │          │          │
┌──────▼───┐ ┌───▼────┐ ┌──▼─────┐
│ Slave 1  │ │Slave 2 │ │Slave 3 │
│ (只读)   │ │(只读)  │ │(只读)  │
└──────────┘ └────────┘ └────────┘

1.2 工作原理

  1. 全量同步:Slave 首次连接 Master 时,Master 执行 BGSAVE 生成 RDB 文件,发送给 Slave
  2. 增量同步:全量同步完成后,Master 将新的写命令实时同步给 Slave
  3. 断线重连:Slave 断线后重连,通过 replid + offset 判断是否可以增量同步

1.3 搭建配置

# slave1.conf
port 6380
# 配置主节点
slaveof 192.168.1.10 6379
# 从节点只读
slave-read-only yes
# 主节点密码
masterauth your_password
# 启动从节点
redis-server slave1.conf

# 验证主从关系
redis-cli -p 6380 INFO replication
# role:slave
# master_host:192.168.1.10
# master_port:6379

1.4 优缺点

优点缺点
配置简单Master 宕机需手动切换
读写分离,提升读性能不具备自动故障转移
数据有副本全量同步时可能阻塞 Master

二、哨兵模式(Sentinel)

2.1 架构

┌──────────┐  ┌──────────┐  ┌──────────┐
│Sentinel 1│  │Sentinel 2│  │Sentinel 3│
│ (监控)    │  │ (监控)   │  │ (监控)   │
└────┬─────┘  └────┬─────┘  └────┬─────┘
     │              │              │
     └──────┬───────┴──────┬──────┘
            │              │
     ┌──────▼──────┐ ┌────▼─────┐
     │   Master    │ │  Slave   │
     │  (读+写)    │ │ (只读)   │
     └─────────────┘ └──────────┘

2.2 工作原理

  1. 监控:Sentinel 不断向 Master/Slave 发送 PING 命令
  2. 主观下线:某个 Sentinel 发现节点无响应,标记为主观下线
  3. 客观下线:超过半数 Sentinel 都报告节点下线,标记为客观下线
  4. 选举 Leader:Sentinel 之间选举一个 Leader 执行故障转移
  5. 故障转移:Leader 选一个 Slave 提升为新 Master,通知其他 Slave 和客户端

2.3 搭建配置

# sentinel1.conf
port 26379

# 监控的 Master(名称 IP 端口 仲裁人数)
sentinel monitor mymaster 192.168.1.10 6379 2

# Master 无响应 30 秒判定下线
sentinel down-after-milliseconds mymaster 30000

# 故障转移超时时间
sentinel failover-timeout mymaster 180000

# 同时只允许1个Slave做同步
sentinel parallel-syncs mymaster 1

# Master 密码
sentinel auth-pass mymaster your_password
# 启动3个Sentinel
redis-sentinel sentinel1.conf
redis-sentinel sentinel2.conf
redis-sentinel sentinel3.conf

2.4 故障转移过程

1. Master宕机
      │
2. Sentinels检测到Master无响应
      │
3. 超过quorum(2)个Sentinel标记为客观下线
      │
4. 选举Leader Sentinel
      │
5. Leader选择最优Slave提升为Master:
   - 排除故障Slave
   - 选择offset最大的Slave(数据最新)
   - 优先级高的Slave优先
      │
6. 其他Slave指向新Master
      │
7. 通知客户端新Master地址
      │
8. 旧Master恢复后变为Slave

2.5 客户端连接

// PHP 客户端连接 Sentinel
$sentinels = [
    'tcp://192.168.1.10:26379',
    'tcp://192.168.1.11:26379',
    'tcp://192.168.1.12:26379',
];

$redis = new RedisSentinel($sentinels, [
    'name'     => 'mymaster',
    'password' => 'your_password',
]);

// 自动路由到当前 Master
$redis->set('key', 'value');

三、Cluster 集群

3.1 架构

┌─────────────────────────────────────────────────────┐
│                  Redis Cluster                       │
│                                                     │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐            │
│  │ Node A  │  │ Node B  │  │ Node C  │            │
│  │Master   │  │Master   │  │Master   │            │
│  │槽0-5460 │  │槽5461-  │  │槽10923- │            │
│  │         │  │ 10922   │  │ 16383   │            │
│  └────┬────┘  └────┬────┘  └────┬────┘            │
│       │            │            │                   │
│  ┌────▼────┐  ┌────▼────┐  ┌────▼────┐            │
│  │ Node A' │  │ Node B' │  │ Node C' │            │
│  │ Slave   │  │ Slave   │  │ Slave   │            │
│  └─────────┘  └─────────┘  └─────────┘            │
└─────────────────────────────────────────────────────┘

3.2 核心概念

哈希槽(Hash Slot)

Redis Cluster 有 16384 个哈希槽,分布在所有 Master 节点上:

# 计算key属于哪个槽
slot = CRC16(key) % 16384

# 示例
# key="user:1001" → CRC16 → slot=12345
# slot 12345 属于 Node C (10923-16383)

节点通信(Gossip协议)

每个节点定期向其他节点发送 PING 消息,交换集群状态信息。

3.3 搭建 Cluster

方式一:手动搭建(6节点,3主3从)

# 创建6个配置文件
for port in 7001 7002 7003 7004 7005 7006; do
  mkdir -p /redis/cluster/$port
  cat > /redis/cluster/$port/redis.conf << EOF
port $port
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
dir /redis/cluster/$port
EOF
done

# 启动6个节点
for port in 7001 7002 7003 7004 7005 7006; do
  redis-server /redis/cluster/$port/redis.conf &
done

# 创建集群
redis-cli --cluster create \
  127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \
  127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \
  --cluster-replicas 1

方式二:Docker Compose 搭建

version: '3.8'
services:
  redis-node-1:
    image: redis:7
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001
    ports:
      - "7001:7001"
    networks:
      - redis-cluster

  redis-node-2:
    image: redis:7
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002
    ports:
      - "7002:7002"
    networks:
      - redis-cluster

  # ... node-3 到 node-6 同理

  redis-cluster-init:
    image: redis:7
    command: >
      bash -c "sleep 10 && 
      echo yes | redis-cli --cluster create 
      redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 
      redis-node-4:7004 redis-node-5:7005 redis-node-6:7006 
      --cluster-replicas 1"
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
      - redis-node-5
      - redis-node-6
    networks:
      - redis-cluster

networks:
  redis-cluster:
    driver: bridge

3.4 客户端使用

// PHP 使用 Redis Cluster
$redis = new RedisCluster(
    null,  // null 表示自动发现节点
    [
        '127.0.0.1:7001',
        '127.0.0.1:7002',
        '127.0.0.1:7003',
    ],
    2,      // 连接超时
    2,      // 读写超时
    true,   // 持久化连接
    'password'
);

// 使用方式与单机一致,客户端自动路由
$redis->set('user:1001', 'Alice');
$redis->set('user:1002', 'Bob');
$redis->set('user:1003', 'Charlie');

// 不同的key可能落在不同节点
// user:1001 → slot 12345 → Node C
// user:1002 → slot 6789  → Node B
// user:1003 → slot 456   → Node A

3.5 Hash Tag

如果需要让多个 key 落在同一个槽,使用 Hash Tag:

# 用 {} 指定hash计算的部分
SET {user:1001}:profile "Alice's profile"
SET {user:1001}:settings '{"theme":"dark"}'
SET {user:1001}:cart "[]"

# 三个key都计算 user:1001 的CRC16,落在同一个槽
# 可以在同一节点执行批量操作
MGET {user:1001}:profile {user:1001}:settings {user:1001}:cart

四、三种方案对比

特性主从复制Sentinel 哨兵Cluster 集群
数据分片是(16384槽)
自动故障转移
读写分离
Master单点瓶颈
最少节点数23+Sentinel6
复杂度
适用场景读多写少中小规模大规模

五、选型建议

数据量 < 10GB?
  ├── 是 → 单机Redis够用
  │       └── 需要高可用?
  │              ├── 是 → Sentinel(3节点+3哨兵)
  │              └── 否 → 单机
  │
  └── 否 → 数据量大/并发高
          └── Redis Cluster(3主3从起步)

生产环境推荐

  • 中小项目:Sentinel 哨兵(1主2从+3哨兵)
  • 大型项目:Redis Cluster(3主3从起步,按需扩展)
  • 极大规模:Cluster + 多机房部署 + 代理层

六、运维注意事项

6.1 内存监控

# 查看各节点内存使用
redis-cli -p 7001 INFO memory | grep used_memory_human
redis-cli -p 7002 INFO memory | grep used_memory_human
redis-cli -p 7003 INFO memory | grep used_memory_human

# 集群整体状态
redis-cli -p 7001 CLUSTER INFO
redis-cli -p 7001 CLUSTER NODES

6.2 扩容(Cluster)

# 新增节点
redis-server /redis/cluster/7007/redis.conf

# 加入集群
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

# 分配槽位(从现有节点迁移部分槽到新节点)
redis-cli --cluster reshard 127.0.0.1:7001 \
  --cluster-from <现有节点ID> \
  --cluster-to <新节点ID> \
  --cluster-slots 1000 \
  --cluster-yes

6.3 数据迁移

# 在线迁移(不停服)
redis-cli --cluster rebalance 127.0.0.1:7001 \
  --cluster-use-empty-masters \
  --cluster-threshold 1

总结

方案核心价值关键限制
主从复制读写分离、数据备份无自动故障转移
Sentinel自动故障转移、高可用单Master写入瓶颈
Cluster数据分片、水平扩展不支持跨槽事务、复杂度高

选择原则:先评估数据量和并发量,小规模用 Sentinel,大规模用 Cluster,不要过度设计。

0

评论 (0)

取消
0:00