Skip to content
清晨的一缕阳光
返回

Redis 高可用架构对比:主从 vs 哨兵 vs Cluster

Redis 高可用架构对比:主从 vs 哨兵 vs Cluster

Redis 提供多种高可用架构方案:主从复制、哨兵模式、Cluster 集群。本文将深入对比这三种方案,帮助你选择最适合的架构。

一、架构概述

1.1 主从复制

┌─────────────┐
│   Master    │  写操作
│ 192.168.1.1 │
│   port 6379 │
└──────┬──────┘
       │ 复制
   ┌───┴───┐
   ▼       ▼
┌─────┐ ┌─────┐
│Slave│ │Slave│  读操作
│192.168│ │192.168│
│.1.2  │ │.1.3  │
└─────┘ └─────┘

特点

1.2 哨兵模式

┌─────────────┐
│   Master    │
│ 192.168.1.1 │
└──────┬──────┘

   ┌───┴───┐
   ▼       ▼
┌─────┐ ┌─────┐
│Slave│ │Slave│
└─────┘ └─────┘
   ▲       ▲
   │       │
┌──┴──┬────┴──┬──┐
│ S1  │  S2   │ S3│  哨兵集群
└─────┘ └─────┘ └───┘

特点

1.3 Cluster 集群

┌─────────┐    ┌─────────┐    ┌─────────┐
│Master 1 │    │Master 2 │    │Master 3 │
│0-5460   │    │5461-10922│   │10923-16383│
└────┬────┘    └────┬────┘    └────┬────┘
     │              │              │
┌────┴────┐    ┌────┴────┐    ┌────┴────┐
│ Slave 1 │    │ Slave 2 │    │ Slave 3 │
└─────────┘    └─────────┘    └─────────┘

特点

二、功能对比

2.1 基本功能

功能主从哨兵Cluster
数据冗余
读写分离
自动故障转移
自动分片
水平扩展
去中心化

2.2 高可用能力

能力主从哨兵Cluster
故障检测手动自动自动
故障转移手动自动自动
恢复时间分钟级秒级秒级
数据丢失可能秒级秒级
可用性99%99.9%99.99%

2.3 扩展能力

能力主从哨兵Cluster
读扩展
写扩展
存储扩展
最大节点数无限制无限制1000
最大数据量单机限制单机限制多机

三、Java 实现对比

3.1 主从模式

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class MasterSlaveExample {
    private static JedisPool masterPool;
    private static JedisPool slavePool;
    
    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(100);
        
        // 主节点(写)
        masterPool = new JedisPool(config, "192.168.1.1", 6379);
        
        // 从节点(读)
        slavePool = new JedisPool(config, "192.168.1.2", 6379);
    }
    
    public static void main(String[] args) {
        // 写操作(主节点)
        try (Jedis master = masterPool.getResource()) {
            master.set("user:1001:name", "Alice");
        }
        
        // 读操作(从节点)
        try (Jedis slave = slavePool.getResource()) {
            String name = slave.get("user:1001:name");
            System.out.println("Name: " + name);
        }
    }
}

3.2 哨兵模式

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;

public class SentinelExample {
    private static JedisSentinelPool pool;
    
    static {
        // 哨兵节点
        Set<String> sentinels = new HashSet<>();
        sentinels.add("192.168.2.1:26379");
        sentinels.add("192.168.2.2:26379");
        sentinels.add("192.168.2.3:26379");
        
        // 连接池配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(100);
        
        // 创建哨兵连接池
        pool = new JedisSentinelPool(
            "mymaster",
            sentinels,
            config,
            "your_password"
        );
    }
    
    public static void main(String[] args) {
        // 自动连接主节点(写)
        try (Jedis jedis = pool.getResource()) {
            jedis.set("user:1001:name", "Alice");
        }
        
        // 自动连接从节点(读)
        try (Jedis jedis = pool.getResource()) {
            String name = jedis.get("user:1001:name");
            System.out.println("Name: " + name);
        }
    }
}

3.3 Cluster 模式

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;

public class ClusterExample {
    private static JedisCluster cluster;
    
    static {
        // 集群节点
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.1.1", 7000));
        nodes.add(new HostAndPort("192.168.1.2", 7001));
        nodes.add(new HostAndPort("192.168.1.3", 7002));
        
        // 连接池配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(100);
        
        // 创建集群连接
        cluster = new JedisCluster(nodes, config);
    }
    
    public static void main(String[] args) {
        // 自动路由到正确节点
        cluster.set("user:1001:name", "Alice");
        String name = cluster.get("user:1001:name");
        
        System.out.println("Name: " + name);
    }
}

四、Golang 实现对比

4.1 主从模式

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()
    
    // 主节点(写)
    master := redis.NewClient(&redis.Options{
        Addr:     "192.168.1.1:6379",
        Password: "your_password",
    })
    
    // 从节点(读)
    slave := redis.NewClient(&redis.Options{
        Addr:     "192.168.1.2:6379",
        Password: "your_password",
    })
    
    // 写操作
    master.Set(ctx, "user:1001:name", "Alice", 0)
    
    // 读操作
    name, _ := slave.Get(ctx, "user:1001:name").Result()
    fmt.Println("Name:", name)
}

4.2 哨兵模式

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()
    
    // 哨兵客户端
    rdb := redis.NewFailoverClient(&redis.FailoverOptions{
        MasterName:    "mymaster",
        SentinelAddrs: []string{
            "192.168.2.1:26379",
            "192.168.2.2:26379",
            "192.168.2.3:26379",
        },
        Password: "your_password",
    })
    
    // 自动路由
    rdb.Set(ctx, "user:1001:name", "Alice", 0)
    name, _ := rdb.Get(ctx, "user:1001:name").Result()
    
    fmt.Println("Name:", name)
}

4.3 Cluster 模式

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
)

func main() {
    ctx := context.Background()
    
    // 集群客户端
    rdb := redis.NewClusterClient(&redis.ClusterOptions{
        Addrs: []string{
            "192.168.1.1:7000",
            "192.168.1.2:7001",
            "192.168.1.3:7002",
        },
        Password: "your_password",
    })
    
    // 自动路由
    rdb.Set(ctx, "user:1001:name", "Alice", 0)
    name, _ := rdb.Get(ctx, "user:1001:name").Result()
    
    fmt.Println("Name:", name)
}

五、性能对比

5.1 基准测试

# 主从模式
redis-benchmark -h 192.168.1.1 -p 6379 -q
# SET: 100000.00 requests per second
# GET: 100000.00 requests per second

# 哨兵模式
# 性能与主从相当,故障转移时有短暂影响

# Cluster 模式
redis-benchmark -h 192.168.1.1 -p 7000 -q
# SET: 80000.00 requests per second
# GET: 80000.00 requests per second
# 略低,因为有路由开销

5.2 延迟对比

操作主从哨兵Cluster
GET~1ms~1ms~1.5ms
SET~1ms~1ms~1.5ms
故障转移手动~5s~5s
跨节点N/AN/A~2ms

5.3 吞吐量对比

场景主从哨兵Cluster
单节点10w QPS10w QPS10w QPS
3 节点读30w QPS30w QPS30w QPS
3 节点写10w QPS10w QPS30w QPS

六、成本对比

6.1 硬件成本

架构最少节点推荐节点硬件成本
主从23
哨兵56
Cluster69

6.2 运维成本

架构部署难度运维难度故障恢复
主从手动
哨兵自动
Cluster自动

6.3 云成本

服务商主从哨兵Cluster
阿里云¥500/月¥1000/月¥2000/月
AWS$100/月$200/月$400/月
自建¥200/月¥500/月¥1000/月

七、选型指南

7.1 选择主从的场景

✅ 推荐:
- 数据量小(< 单机容量)
- 读多写少
- 预算有限
- 运维能力弱

❌ 不推荐:
- 需要自动故障转移
- 写操作频繁
- 数据量大

7.2 选择哨兵的场景

✅ 推荐:
- 需要高可用
- 数据量中等
- 自动故障转移
- 读写分离

❌ 不推荐:
- 需要水平扩展
- 数据量超大
- 写操作频繁

7.3 选择 Cluster 的场景

✅ 推荐:
- 数据量大(> 单机容量)
- 需要水平扩展
- 高并发写入
- 大规模部署

❌ 不推荐:
- 数据量小
- 预算有限
- 运维能力弱

八、架构演进

8.1 从小到大的演进路径

阶段 1:单机 Redis
┌─────────┐
│  Redis  │
└─────────┘

阶段 2:主从复制
┌─────────┐
│ Master  │
└────┬────┘

┌────┴────┐
│  Slave  │
└─────────┘

阶段 3:哨兵模式
┌─────────┐
│ Master  │
└────┬────┘    ┌─────┐
     │         │ S1  │
┌────┴────┐    ├─────┤
│  Slave  │    │ S2  │
└─────────┘    ├─────┤
               │ S3  │
               └─────┘

阶段 4:Cluster 集群
┌─────┐ ┌─────┐ ┌─────┐
│ M1  │ │ M2  │ │ M3  │
└──┬──┘ └──┬──┘ └──┬──┘
   │        │        │
┌──┴──┐ ┌──┴──┐ ┌──┴──┐
│ S1  │ │ S2  │ │ S3  │
└─────┘ └─────┘ └─────┘

8.2 迁移方案

主从迁移到哨兵

# 1. 部署哨兵节点
# 2. 配置哨兵监控
# 3. 验证故障转移
# 4. 切换客户端配置

哨兵迁移到 Cluster

# 1. 部署 Cluster 集群
# 2. 使用 redis-shake 迁移数据
# 3. 验证数据完整性
# 4. 切换客户端配置
# 5. 下线哨兵集群

九、最佳实践

9.1 主从最佳实践

✅ 推荐:
- 至少 1 主 2 从
- 配置合理的超时时间
- 定期备份
- 监控主从延迟

❌ 避免:
- 主从同机
- 无监控
- 无备份

9.2 哨兵最佳实践

✅ 推荐:
- 至少 3 个哨兵
- quorum = 2
- 哨兵与 Redis 分离部署
- 配置告警通知

❌ 避免:
- 哨兵数量过少
- quorum 设置过高
- 哨兵与主节点同机

9.3 Cluster 最佳实践

✅ 推荐:
- 至少 3 主 3 从
- 节点跨机房部署
- 配置合理的超时时间
- 定期备份和演练

❌ 避免:
- 单机房部署
- 超时时间过短
- 无备份

十、故障处理

10.1 主从故障

# 1. 主节点故障
# 手动提升从节点为主
redis-cli -p 6379 SLAVEOF NO ONE

# 2. 更新应用配置
# 3. 重新配置从节点
redis-cli -p 6379 SLAVEOF new_master_ip 6379

10.2 哨兵故障

# 1. 哨兵节点故障
# 自动故障转移

# 2. 检查新主节点
redis-cli -p 26379 SENTINEL MASTER mymaster

# 3. 恢复故障哨兵
redis-server /etc/redis/sentinel.conf

10.3 Cluster 故障

# 1. 主节点故障
# 自动故障转移

# 2. 检查集群状态
redis-cli --cluster check 192.168.1.1:7000

# 3. 如果需要,手动修复
redis-cli --cluster fix 192.168.1.1:7000

总结

Redis 高可用架构对比总结:

架构优势劣势适用场景
主从简单、成本低无自动故障转移小规模、读多写少
哨兵自动故障转移、中等成本无法水平扩展中等规模、高可用
Cluster水平扩展、高可用复杂、成本高大规模、高并发

选型建议

根据业务规模和需求选择合适的架构!

参考资料


分享这篇文章到:

上一篇文章
RAG 质量保障体系构建
下一篇文章
Redis 大 Key 与热 Key 问题分析与解决