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

Redis 集群部署方案全解析

Redis 集群部署方案全解析

Redis 提供了多种部署方案,从单机到集群,每种方案都有其适用场景。本文将全面解析各种部署方案,帮助你选择最适合的架构。

一、部署方案对比

1.1 方案总览

Redis 部署方案演进:

单机版 → 主从复制 → 哨兵模式 → Cluster 集群

┌─────────────────────────────────────────┐
│ 方案        │ 可用性 │ 扩展性 │ 复杂度 │
├─────────────────────────────────────────┤
│ 单机版      │   低   │   无   │   低   │
│ 主从复制    │   中   │   低   │   中   │
│ 哨兵模式    │   高   │   中   │   高   │
│ Cluster     │   高   │   高   │   高   │
└─────────────────────────────────────────┘

1.2 详细对比

特性单机主从哨兵Cluster
节点数12+3+6+
故障转移手动手动自动自动
读写分离不支持支持支持支持
水平扩展不支持不支持不支持支持
数据分片
适用 QPS<1 万<5 万<10 万>10 万
适用数据量<10GB<20GB<50GB不限

二、单机版部署

2.1 适用场景

2.2 部署配置

# redis.conf 基础配置
bind 127.0.0.1
port 6379
daemonize yes
pidfile /var/run/redis/redis-server.pid
logfile /var/log/redis/redis-server.log

# 数据目录
dir /var/lib/redis

# 持久化
save 900 1
save 300 10
save 60 10000

# 内存限制
maxmemory 2gb
maxmemory-policy allkeys-lru

# 安全配置
requirepass your_password

2.3 启动脚本

#!/bin/bash
# start_redis.sh

REDIS_HOME="/opt/redis"
REDIS_CONF="$REDIS_HOME/redis.conf"

# 创建目录
mkdir -p /var/run/redis
mkdir -p /var/log/redis
mkdir -p /var/lib/redis

# 启动 Redis
$REDIS_HOME/bin/redis-server $REDIS_CONF

# 验证启动
sleep 2
$REDIS_HOME/bin/redis-cli ping

三、主从复制部署

3.1 适用场景

3.2 架构设计

主从复制架构:

┌─────────────┐
│   Master    │  192.168.1.10:6379
│  (读写)     │
└──────┬──────┘
       │ 复制
       ├─────────────┐
       ▼             ▼
┌─────────────┐ ┌─────────────┐
│  Slave 1    │ │  Slave 2    │
│  (只读)     │ │  (只读)     │
│ 192.168.1.11│ │ 192.168.1.12│
└─────────────┘ └─────────────┘

3.3 主节点配置

# Master 配置 (redis-master.conf)
bind 0.0.0.0
port 6379
daemonize yes
pidfile /var/run/redis/redis-master.pid
logfile /var/log/redis/redis-master.log
dir /var/lib/redis/master

# 密码
requirepass master_password

# 复制认证密码
masterauth master_password

# 持久化
save 900 1
save 300 10
save 60 10000

# 内存限制
maxmemory 4gb
maxmemory-policy allkeys-lru

3.4 从节点配置

# Slave 配置 (redis-slave.conf)
bind 0.0.0.0
port 6379
daemonize yes
pidfile /var/run/redis/redis-slave.pid
logfile /var/log/redis/redis-slave.log
dir /var/lib/redis/slave

# 密码
requirepass slave_password

# 复制认证
masterauth master_password

# 指定主节点
replicaof 192.168.1.10 6379

# 只读模式
replica-read-only yes

# 持久化(可选)
save 900 1

3.5 启动顺序

#!/bin/bash
# start_master_slave.sh

# 1. 启动主节点
redis-server /etc/redis/redis-master.conf
sleep 2

# 2. 启动从节点 1
redis-server /etc/redis/redis-slave1.conf
sleep 2

# 3. 启动从节点 2
redis-server /etc/redis/redis-slave2.conf
sleep 2

# 4. 验证复制状态
redis-cli -h 192.168.1.10 -a master_password INFO replication

3.6 读写分离实现

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
import java.util.Random;

public class ReadWriteSeparation {
    private JedisPool masterPool;
    private List<JedisPool> slavePools;
    private Random random = new Random();
    
    public ReadWriteSeparation(JedisPool masterPool, List<JedisPool> slavePools) {
        this.masterPool = masterPool;
        this.slavePools = slavePools;
    }
    
    /**
     * 写操作(路由到主节点)
     */
    public void set(String key, String value) {
        try (Jedis jedis = masterPool.getResource()) {
            jedis.set(key, value);
        }
    }
    
    /**
     * 读操作(随机路由到从节点)
     */
    public String get(String key) {
        if (slavePools.isEmpty()) {
            try (Jedis jedis = masterPool.getResource()) {
                return jedis.get(key);
            }
        }
        
        // 随机选择一个从节点
        int index = random.nextInt(slavePools.size());
        try (Jedis jedis = slavePools.get(index).getResource()) {
            return jedis.get(key);
        }
    }
    
    /**
     * 删除操作(路由到主节点)
     */
    public void delete(String key) {
        try (Jedis jedis = masterPool.getResource()) {
            jedis.del(key);
        }
    }
}

四、哨兵模式部署

4.1 适用场景

4.2 架构设计

哨兵模式架构(3 哨兵 + 1 主 2 从):

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Sentinel 1 │    │  Sentinel 2 │    │  Sentinel 3 │
│ 192.168.1.20│    │ 192.168.1.21│    │ 192.168.1.22│
│   port 26379│    │   port 26379│    │   port 26379│
└─────────────┘    └─────────────┘    └─────────────┘
       │                  │                  │
       └──────────────────┼──────────────────┘
                          │ 监控
       ┌──────────────────┼──────────────────┐
       ▼                  ▼                  ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Master    │    │  Slave 1    │    │  Slave 2    │
│ 192.168.1.10│    │ 192.168.1.11│    │ 192.168.1.12│
└─────────────┘    └─────────────┘    └─────────────┘

4.3 哨兵配置

# Sentinel 配置 (redis-sentinel.conf)
port 26379
daemonize yes
pidfile /var/run/redis/redis-sentinel.pid
logfile /var/log/redis/redis-sentinel.log

# 监控主节点
# sentinel monitor <master-name> <ip> <port> <quorum>
sentinel monitor mymaster 192.168.1.10 6379 2

# 认证密码
sentinel auth-pass mymaster master_password

# 故障判定时间(毫秒)
sentinel down-after-milliseconds mymaster 5000

# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 60000

# 同时复制的从节点数
sentinel parallel-syncs mymaster 1

# 通知脚本(可选)
# sentinel notification-script mymaster /var/redis/notify.sh

# 客户端重新连接配置
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

4.4 启动哨兵集群

#!/bin/bash
# start_sentinel_cluster.sh

# 1. 启动主从节点(参考前面)
# ...

# 2. 启动哨兵 1
redis-sentinel /etc/redis/redis-sentinel1.conf
sleep 2

# 3. 启动哨兵 2
redis-sentinel /etc/redis/redis-sentinel2.conf
sleep 2

# 4. 启动哨兵 3
redis-sentinel /etc/redis/redis-sentinel3.conf
sleep 2

# 5. 验证哨兵状态
redis-cli -h 192.168.1.20 -p 26379 INFO sentinel

4.5 Java 连接哨兵

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 {
    public static JedisSentinelPool createSentinelPool() {
        // 哨兵节点
        Set<String> sentinels = new HashSet<>();
        sentinels.add("192.168.1.20:26379");
        sentinels.add("192.168.1.21:26379");
        sentinels.add("192.168.1.22:26379");
        
        // 连接池配置
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(50);
        poolConfig.setMaxIdle(20);
        poolConfig.setMinIdle(5);
        poolConfig.setMaxWaitMillis(3000);
        
        // 创建哨兵连接池
        return new JedisSentinelPool(
            "mymaster",           // 主节点名称
            sentinels,            // 哨兵节点集合
            poolConfig,           // 连接池配置
            "master_password"     // 密码
        );
    }
    
    public static void main(String[] args) {
        JedisSentinelPool pool = createSentinelPool();
        
        try (Jedis jedis = pool.getResource()) {
            // 自动连接到主节点
            jedis.set("test", "value");
            System.out.println(jedis.get("test"));
        }
        
        pool.close();
    }
}

4.6 故障转移测试

# 1. 查看当前主节点
redis-cli -h 192.168.1.20 -p 26379 sentinel get-master-addr-by-name mymaster

# 2. 模拟主节点故障
redis-cli -h 192.168.1.10 -a master_password DEBUG sleep 1000

# 3. 观察哨兵日志
tail -f /var/log/redis/redis-sentinel.log

# 4. 查看新的主节点
redis-cli -h 192.168.1.20 -p 26379 sentinel get-master-addr-by-name mymaster

# 5. 验证数据完整性
redis-cli -h <new-master-ip> -a master_password keys "*" | wc -l

五、Cluster 集群部署

5.1 适用场景

5.2 架构设计

Cluster 集群架构(6 节点,3 主 3 从):

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Master 1   │    │  Master 2   │    │  Master 3   │
│  0-5460     │    │ 5461-10922  │    │ 10923-16383 │
│ 192.168.1.10│    │ 192.168.1.11│    │ 192.168.1.12│
│   port 7000 │    │   port 7001 │    │   port 7002 │
└──────┬──────┘    └──────┬──────┘    └──────┬──────┘
       │                  │                  │
┌──────┴──────┐    ┌──────┴──────┐    ┌──────┴──────┐
│  Slave 1    │    │  Slave 2    │    │  Slave 3    │
│ 192.168.1.13│    │ 192.168.1.14│    │ 192.168.1.15│
│   port 7003 │    │   port 7004 │    │   port 7005 │
└─────────────┘    └─────────────┘    └─────────────┘

5.3 节点配置

# Cluster 节点配置 (redis-cluster-node.conf)
bind 0.0.0.0
port 7000
daemonize yes
pidfile /var/run/redis/redis-7000.pid
logfile /var/log/redis/redis-7000.log
dir /var/lib/redis/7000

# 开启集群模式
cluster-enabled yes

# 集群配置文件(自动生成)
cluster-config-file nodes-7000.conf

# 节点超时时间(毫秒)
cluster-node-timeout 5000

# 密码
requirepass cluster_password
masterauth cluster_password

# 持久化
save 900 1
save 300 10
save 60 10000

# 内存限制
maxmemory 4gb
maxmemory-policy allkeys-lru

5.4 创建集群

# 1. 启动所有节点
for port in 7000 7001 7002 7003 7004 7005; do
    redis-server /etc/redis/redis-cluster-$port.conf
done

sleep 3

# 2. 创建集群(3 主 3 从)
redis-cli --cluster create \
    192.168.1.10:7000 192.168.1.11:7001 192.168.1.12:7002 \
    192.168.1.13:7003 192.168.1.14:7004 192.168.1.15:7005 \
    --cluster-replicas 1 \
    --cluster-yes \
    -a cluster_password

# 3. 查看集群状态
redis-cli -h 192.168.1.10 -p 7000 -a cluster_password cluster info

# 4. 查看节点信息
redis-cli -h 192.168.1.10 -p 7000 -a cluster_password cluster nodes

5.5 Java 连接 Cluster

import redis.clients.jedis.ClusterCommandArguments;
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 {
    public static JedisCluster createCluster() {
        // 集群节点
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.1.10", 7000));
        nodes.add(new HostAndPort("192.168.1.11", 7001));
        nodes.add(new HostAndPort("192.168.1.12", 7002));
        nodes.add(new HostAndPort("192.168.1.13", 7003));
        nodes.add(new HostAndPort("192.168.1.14", 7004));
        nodes.add(new HostAndPort("192.168.1.15", 7005));
        
        // 连接池配置
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(50);
        poolConfig.setMinIdle(10);
        
        // 创建集群连接
        return new JedisCluster(
            nodes,
            5000,  // 超时时间
            5000,  // 连接超时
            5,     // 最大重试次数
            "cluster_password",
            poolConfig
        );
    }
    
    public static void main(String[] args) {
        JedisCluster cluster = createCluster();
        
        // 自动路由到正确节点
        cluster.set("user:1001:name", "张三");
        String value = cluster.get("user:1001:name");
        System.out.println(value);
        
        cluster.close();
    }
}

六、方案选型建议

6.1 选型决策树

选择部署方案决策树:

1. 是否需要高可用?
   ├── 否 → 单机版
   └── 是 → 2

2. 数据量是否 > 50GB?
   ├── 否 → 3
   └── 是 → Cluster

3. QPS 是否 > 10 万?
   ├── 否 → 4
   └── 是 → Cluster

4. 是否需要自动故障转移?
   ├── 否 → 主从复制
   └── 是 → 哨兵模式

5. 预算是否充足?
   ├── 否 → 主从复制(2 节点)
   └── 是 → 哨兵模式(3 哨兵 + 1 主 2 从)

6.2 推荐配置

规模推荐方案节点数内存预估成本
小型单机版14GB
中型主从复制38GB
大型哨兵模式616GB
超大型Cluster6+32GB+很高

七、总结

7.1 各方案核心特点

  1. 单机版

    • 优点:简单、成本低
    • 缺点:单点故障、无法扩展
    • 适用:开发测试、小规模应用
  2. 主从复制

    • 优点:读写分离、数据备份
    • 缺点:手动故障转移
    • 适用:读多写少、中等规模
  3. 哨兵模式

    • 优点:自动故障转移、高可用
    • 缺点:无法水平扩展
    • 适用:高可用要求、中大规模
  4. Cluster 集群

    • 优点:水平扩展、自动分片
    • 缺点:复杂度高、运维成本高
    • 适用:大数据量、高并发

参考资料


分享这篇文章到:

上一篇文章
RocketMQ 系列完整学习指南
下一篇文章
Kafka 性能调优进阶实战