【Redis】集群搭建(主从、哨兵、集群模式)

一、主从模式

1、概述

通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此,Redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

Redis主从同步策略:主从数据库刚刚连接的时候,采用全量同步来初始化slave节点。salve正常工作时,采用增量同步来将主服务器发生的写操作同步到从服务器。无论如何,redis首先会尝试进行增量同步,如不成功,要求从数据库进行全量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。

  • 全量同步:当一个从数据库启动后,会向主数据库发送 SYNC 命令。主数据库接收到 SYNC 命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。

  • 增量复制:从数据库发送 PSYNC 命令,格式为 PSYNC 主数据库的运行ID 断开前最新的命令偏移量。主数据库收到 PSYNC 命令后,首先会判断从数据库传送来的运行ID是否和自己的运行ID相同(确保从数据库之前确实是和自己同步的,以免从数据库拿到错误的数据),然后判断从数据库最后同步成功的命令偏移量是否在积压队列中。两个条件都满足的话就可以执行增量复制,并将积压队列中相应的命令发送给从数据库。如果此次重连不满足增量复制的条件,主数据库会进行一次全量同步。

缺点:master节点在主从模式中唯一,若master挂掉,则redis无法对外提供写服务。

2、部署配置

主数据库不需要配置,从数据库的配置文件(redis.conf)中加入 slaveof 数据库地址 主数据库端口 即可。

# 检查Redis是否安装
redis-cli --version
# 若未安装,以Ubuntu为例:
sudo apt update
sudo apt install redis-server

# 创建配置文件目录
mkdir -p redis/{master,slave}

# 编辑主节点的 Redis 配置文件
tee redis/master/redis.conf << EOF
port 6379             # 默认端口
bind 0.0.0.0          # 允许远程连接(或指定主节点IP)
protected-mode no     # 关闭保护模式(仅测试环境,生产环境需配置密码)
requirepass "your_master_password"  # 设置主节点密码(可选)
daemonize yes
pidfile /var/run/redis_6379.pid
logfile "master.log"
dir ./data
EOF

# 配置从节点
tee redis/master/redis.conf << EOF
port 6380             
bind 0.0.0.0
protected-mode no
masterauth "your_master_password"
daemonize yes
pidfile /var/run/redis_6380.pid
logfile "slave.log"
dir ./data
replicaof 127.0.0.1 6379
EOF

# 重启Redis 服务
sudo systemctl restart redis-server
sudo systemctl restart redis-server

3、验证主从复制

在主节点写入数据

redis-cli -h <master_ip> -a your_master_password
127.0.0.1:6379> SET key1 "Hello from Master"
OK

在从节点读取数据

redis-cli -h <slave_ip> -p 6380
127.0.0.1:6380> GET key1
"Hello from Master"

检查复制状态

在从节点执行:

127.0.0.1:6380> INFO replication
# 应显示类似:
# role:slave
# master_host:<master_ip>
# master_port:6379
# master_link_status:up

二、哨兵模式

1、概述

Redis 哨兵模式(Sentinel)是 Redis 官方提供的一种高可用性(High Availability, HA)解决方案。它的核心目标是在主从复制架构的基础上,解决主节点(Master)故障时自动进行故障转移(Failover),从而最大限度地减少服务中断时间。

使用sentinel模式的时候,客户端就不要直接连接Redis,而是连接sentinel的ip和port,由sentinel来提供具体的可提供服务的Redis实现,这样当master节点挂掉以后,sentinel就会感知并将新的master节点提供给使用者。

2、架构组成

  • Redis 主节点(Master):提供读写服务。

  • Redis 从节点(Slave/Replica):复制主节点的数据,提供读服务(可选),并作为主节点的候补。

  • Redis 哨兵节点(Sentinel)

    • 本质上是一个特殊的 Redis 实例(运行 redis-sentinelredis-server --sentinel)。

    • 不存储应用数据,只负责监控和管理 Redis 主从节点。

    • 必须部署多个哨兵节点(通常是 3 个或 5 个,且为奇数) 以形成哨兵集群,自身实现高可用和决策仲裁。

    • 哨兵节点之间互相通信、互相监控。

3、哨兵模式的核心工作流程

  1. 监控(Monitoring)
    • 每个哨兵节点会定期(可配置,如每秒一次)向它配置监控的所有主节点、从节点以及其他哨兵节点发送 PING 命令。
    • 根据 PING 的回复(有效回复、无效回复、无回复)和超时时间来判断实例的状态(主观下线)。
  2. 主观下线(Subjectively Down, SDOWN)
    • 如果某个哨兵节点在配置的时间内(down-after-milliseconds)没有收到某个 Redis 实例(主、从或其它哨兵)的有效 PING 回复,该哨兵会主观地将这个实例标记为“主观下线”。
    • 主观下线是单个哨兵的局部判断。
  3. 客观下线(Objectively Down, ODOWN)
    • 当哨兵将一个主节点标记为主观下线后,它会向其他哨兵节点发送 SENTINEL is-master-down-by-addr 命令,询问它们是否也认为该主节点已下线。
    • 如果收到足够数量(由配置项 quorum 指定)的哨兵节点确认(它们也认为该主节点主观下线),那么发起询问的哨兵就会将主节点标记为“客观下线”。
    • 达到 quorum 值是触发后续自动故障转移的必要条件
    • 客观下线是整个哨兵集群达成共识的判断,表明主节点真的可能挂了。
  4. 选举领头哨兵(Leader Election)
    • 一旦主节点被判定为客观下线,哨兵集群需要选举出一个领头哨兵(Leader Sentinel) 来负责执行本次故障转移操作。
    • 选举基于 Raft 算法的变种实现:
      • 发现主节点客观下线的哨兵会向其他哨兵发送请求,要求投票选自己为领头哨兵。
      • 哨兵遵循“先到先得”和“目标纪元(epoch)更大优先”的原则投票。
      • 获得多数票(> N/2,N 是哨兵总数)的哨兵成为领头哨兵。
      • 如果一轮投票未选出,会在随机延时后开启新一轮投票。
  5. 故障转移(Failover)
    • 被选出的领头哨兵负责执行故障转移:
      • 选择新主节点:根据规则(优先级 replica-priority、复制偏移量、Run ID 等)从旧主节点的从节点中选出一个最合适的作为新的主节点。
      • 提升新主节点:向选中的从节点发送 SLAVEOF no one 命令,将其提升为主节点。
      • 重新配置其他从节点:向其他从节点发送 SLAVEOF 命令,让它们改为复制新的主节点。
      • 更新配置:将旧主节点(如果恢复)更新为新的主节点的从节点。
      • 通知客户端:通过发布订阅功能更新配置信息,客户端连接到哨兵时会获取到新的主节点地址。
  6. 配置传播(Configuration Propagation)
    • 领头哨兵会将故障转移后产生的新配置(新的主节点是谁)广播给其他哨兵节点。
    • 所有哨兵节点最终会更新自己的内部配置,记录当前的主节点信息。

4、哨兵模式的优势

  • 高可用性:自动故障转移大大减少了主节点故障导致的停机时间。
  • 监控与告警:提供对 Redis 实例运行状态的持续监控和通知能力。
  • 服务发现:客户端无需硬编码主节点地址,通过连接哨兵即可获取当前有效的主节点地址。
  • 官方支持:是 Redis 原生的 HA 方案,兼容性好,社区支持完善。
  • 相对简单:相比于 Redis Cluster,部署和配置相对简单,尤其适用于中小规模集群。

5、哨兵模式的局限与注意事项

  1. 脑裂问题(Split-Brain)

    • 在网络分区(Network Partition)的情况下,可能出现两个区域都认为自己是主节点的情况,导致数据不一致。
    • 缓解措施
      • 设置 min-replicas-to-write:主节点必须至少有 N 个从节点连接才允许写入。
      • 设置 min-replicas-max-lag:从节点复制延迟不能超过 M 秒才算有效连接。
      • 使用合理的 quorum 值(大于哨兵总数一半)。
      • 部署在可靠的网络环境中。
  2. 故障转移时间:从主节点故障到新主节点提供服务,存在一定延迟(秒级到几十秒),期间服务可能短暂不可用。

  3. 配置复杂性:需要部署和管理多个哨兵实例,配置项较多。

  4. 不解决数据分片(Sharding):哨兵只负责高可用,不解决单节点数据容量和写性能瓶颈问题。需要横向扩展写能力时,应使用 Redis Cluster。

  5. 资源消耗:哨兵进程本身需要消耗一定的 CPU 和内存资源。

  6. 客户端支持:客户端需要支持哨兵协议才能正确地从哨兵获取主节点信息。

6、哨兵模式集群搭建

以下是基于 3 个 Redis 节点(1 主 + 2 从)和 3 个 Sentinel 节点的完整搭建流程(以 Linux 为例):

(1)部署建议

  1. 哨兵数量至少 3 个,且部署在独立的、物理隔离的机器或虚拟机上。奇数个(3,5)有利于避免选举僵局。避免将多个哨兵部署在同一台故障域机器上。
  2. quorum:通常设置为 (哨兵总数 / 2) + 1(如 3 个哨兵时设为 2)。这个值决定了判断主节点客观下线所需的票数。
  3. 网络:确保 Redis 实例之间、哨兵之间、哨兵与 Redis 实例之间的网络通信稳定、低延迟。
  4. 持久化配置:确保主节点和从节点都配置了合适的持久化策略(RDB 或 AOF),以保证故障转移后数据不丢失。
  5. 监控哨兵本身:哨兵节点也需要被监控,防止哨兵集群失效。

(2)环境规划

角色IP端口
Master127.0.0.16379
Replica-1127.0.0.16380
Replica-2127.0.0.16381
Sentinel-1127.0.0.126379
Sentinel-2127.0.0.126380
Sentinel-3127.0.0.126381

生产环境需将节点分散在不同服务器,此处用单机多端口演示

(3)节点配置

# 创建配置文件目录
mkdir -p redis/{master,slave1,slave2} sentinel/{sentinel1,sentinel2,sentinel3}

# 配置 Master(6379)
tee redis/master/redis.conf << EOF
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
logfile "master.log"
dir ./data
EOF

# 配置 Replica-1(6380)
tee redis/slave1/redis.conf << EOF
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
logfile "slave1.log"
dir ./data
replicaof 127.0.0.1 6379  # 指向Master
EOF

# 配置 Replica-2(6381)
tee redis/slave2/redis.conf << EOF
port 6381
daemonize yes
pidfile /var/run/redis_6381.pid
logfile "slave2.log"
dir ./data
replicaof 127.0.0.1 6379  # 指向Master
EOF

# Sentinel-1 配置(26379)
tee redis/sentinel1/redis.conf << EOF
port 26379
daemonize yes
logfile "sentinel1.log"
sentinel monitor mymaster 127.0.0.1 6379 2  		# 监控Master,quorum=2
sentinel down-after-milliseconds mymaster 5000  # 5秒无响应判为主观下线
sentinel failover-timeout mymaster 60000  			# 故障转移超时60秒
sentinel parallel-syncs mymaster 1  						# 同时同步的从节点数
EOF

# Sentinel-2 配置(26379)
cp sentinel/sentinel1/sentinel.conf sentinel/sentinel2/sentinel.conf
sed -i 's/26379/26380/g; s/sentinel1/sentinel2/g' sentinel/sentinel2/sentinel.conf

# Sentinel-3 配置(26379)
cp sentinel/sentinel1/sentinel.conf sentinel/sentinel3/sentinel.conf
sed -i 's/26379/26381/g; s/sentinel1/sentinel3/g' sentinel/sentinel3/sentinel.conf

(4)启动集群

#启动 Redis 主从节点
redis-server redis/master/redis.conf
redis-server redis/slave1/redis.conf
redis-server redis/slave2/redis.conf

# 启动 Sentinel 节点
redis-sentinel sentinel/sentinel1/sentinel.conf
redis-sentinel sentinel/sentinel2/sentinel.conf
redis-sentinel sentinel/sentinel3/sentinel.conf

# 验证主从状态
redis-cli -p 6379 info replication  # 查看Master角色和Slaves连接
redis-cli -p 6380 info replication  # 确认Slave复制状态

(5)测试故障转移

# 检查 Sentinel 监控状态
redis-cli -p 26379 sentinel master mymaster
# 输出应显示主节点信息及哨兵数量

# 模拟 Master 宕机
kill -9 $(pgrep -f "redis-server.*6379")

# 观察故障转移(约 10-30 秒)
tail -f sentinel/sentinel1/sentinel.log  # 搜索 +switch-master 事件

# 检查新 Master
redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
# 输出新Master的IP和端口(如 127.0.0.1 6380)

# 重启旧 Master,它将自动变为新 Master 的从节点
redis-server redis/master/redis.conf
redis-cli -p 6379 info replication  # 确认角色变为 slave

(6)客户端连接哨兵集群

使用支持 Sentinel 的客户端(如 Redis 的 redis-py):

from redis.sentinel import Sentinel

sentinel_list = [('127.0.0.1', 26379), ('127.0.0.1', 26380), ('127.0.0.1', 26381)]
sentinel = Sentinel(sentinel_list, socket_timeout=0.5)

# 获取当前主节点
master = sentinel.discover_master('mymaster')
print("Master:", master)

# 获取从节点列表
slaves = sentinel.discover_slaves('mymaster')
print("Slaves:", slaves)

# 写入操作(自动路由到Master)
master_client = sentinel.master_for('mymaster')
master_client.set('key', 'value')

# 读取操作(可路由到Slave)
slave_client = sentinel.slave_for('mymaster')
print(slave_client.get('key'))

使用sentinel模式的时候,客户端就不要直接连接Redis,而是连接sentinel的ip和port,由sentinel来提供具体的可提供服务的Redis实现,这样当master节点挂掉以后,sentinel就会感知并将新的master节点提供给使用者。

三、集群模式

Redis 集群模式(Redis Cluster)是 Redis 官方提供的分布式解决方案,用于解决单机 Redis 在数据容量并发性能上的瓶颈。它通过数据分片(Sharding)高可用(High Availability)自动故障转移三大核心能力,实现大规模数据的分布式存储与访问。

Redis 集群模式通过创新的 哈希槽分片去中心化架构,实现了真正意义上的分布式存储。虽然牺牲了部分兼容性(如跨槽位事务),但其水平扩展能力和高可用设计使其成为处理海量数据的首选方案。对于需要突破单机瓶颈的场景(如百万QPS、TB级数据),集群模式是 Redis 生态中最成熟的分布式解决方案。

1、核心设计目标

  • 水平扩展

    • 数据分散存储在多个节点(分片),突破单机内存/性能限制

    • 支持动态增删节点,容量可线性扩展至 1000+ 节点

  • 高可用

    • 主从复制架构 + 自动故障转移(类似哨兵但内置实现)

    • 部分节点故障时仍能提供服务

  • 高性能

    • 并行操作不同分片,提升整体吞吐量
  • 去中心化架构

    • 无代理层,节点间通过 Gossip 协议通信

2、关键架构原理

(1)数据分片机制(Sharding)

  • 哈希槽(Hash Slot)
    • 整个集群划分为 16384 个固定槽位(0-16383)
    • 每个键通过 CRC16 算法计算哈希值,再对 16384 取模确定所属槽位:slot = CRC16(key) mod 16384
  • 槽位分配
    • 主节点负责处理特定范围的槽位(如 Node1: 0-5000, Node2: 5001-10000)
    • 集群启动时自动分配槽位,支持动态重分配(CLUSTER ADDSLOTS

(2)节点角色

角色数量要求职责
主节点≥ 3处理读写请求,管理槽位
从节点每个主节点 ≥1复制主节点数据,故障时接替主节点

⚠️ 最小集群配置:3 主节点 + 3 从节点(保证高可用)

(3)节点通信协议

  • Gossip 协议
    • 节点间周期性交换信息(PING/PONG 消息)
    • 携带数据:节点状态、槽位映射、故障标识等
    • 特点:低带宽消耗,最终一致性
  • 通信端口
    • 客户端访问端口(如 6379)
    • 集群总线端口(客户端端口 + 10000,如 16379),用于节点间通信

3、工作流程详解

(1)客户端请求路由

Client NodeA NodeB SET key value CRC16(key) mod 16384 = 5000 直接执行命令 -MOVED 5000 192.168.1.2:6379 SET key value OK alt [槽位属于 NodeA] [槽位属于 NodeB] Client NodeA NodeB
  • 重定向机制
    • 客户端首次连接可能收到 -MOVED 响应,包含目标节点地址
    • 智能客户端(如 JedisCluster)会缓存槽位映射表,自动路由请求

(2)故障检测与转移

  1. 主观下线(PFAIL)
    • 节点 A 在 cluster-node-timeout 内未收到节点 B 的响应,标记 B 为 PFAIL
  2. 客观下线(FAIL)
    • 节点 A 通过 Gossip 协议广播 B 的 PFAIL 状态
    • 当多数主节点确认 B 为 PFAIL 时,触发客观下线
  3. 从节点选举
    • 故障主节点的从节点发起选举(基于 Raft 变种)
    • 获胜从节点执行 SLAVEOF NO ONE 升级为主节点
  4. 槽位接管
    • 新主节点广播 PONG 消息通知集群更新拓扑

(3)数据迁移(Resharding)

  • 场景:扩容/缩容时重新分配槽位
  • 命令redis-cli --cluster reshard
  • 过程
    1. 目标节点准备导入槽位(CLUSTER SETSLOT <slot> IMPORTING <src-id>
    2. 源节点准备导出槽位(CLUSTER SETSLOT <slot> MIGRATING <dst-id>
    3. 批量迁移键值(MIGRATE 命令原子迁移单个键)
    4. 广播槽位所有权变更

4、核心特性与限制

✅ 优势
特性说明
自动分片数据均匀分布,无需客户端处理分片逻辑
无缝扩缩容支持动态增删节点,数据自动再平衡
内置高可用主从切换无需额外组件(如 Sentinel)
部分故障容忍只要主节点及其从节点不同时宕机,集群仍可用
批量操作优化支持跨节点 {tag} 的批量命令(如 MSET
⚠️ 限制与注意事项
限制项说明
不支持多数据库仅能用 db0,SELECT 命令被禁用
跨节点事务受限仅支持相同槽位的键事务(可通过 Hash Tag 强制键同槽位)
批量操作限制跨槽位 mget/mset 需拆分为单节点操作
Lua 脚本约束脚本中所有键必须在同一槽位(EVAL 需用 {tag}
键大小限制单个键值不能超过 512MB
网络分区风险可能出现脑裂(可通过 min-slaves-to-write 缓解)

5、集群搭建示例(6 节点)

# 创建节点目录
mkdir -p redis-cluster/{7000..7005}

# 基础配置 (以 7000 为例)
cat > redis-cluster/7000/redis.conf <<EOF
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

# 复制配置到其他节点
for port in {7001..7005}; do 
  cp redis-cluster/7000/redis.conf redis-cluster/$port/
  sed -i "s/7000/$port/g" redis-cluster/$port/redis.conf
done

# 启动所有节点
for port in {7000..7005}; do
  redis-server redis-cluster/$port/redis.conf
done

# 创建集群 (3主3从)
redis-cli --cluster create 127.0.0.1:7000 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 \
  --cluster-replicas 1  # 每个主节点配1个从节点

6、集群扩容

# 1. 准备新节点配置
mkdir redis-cluster/7006 && cat > redis-cluster/7006/redis.conf <<EOF
port 7006
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF

mkdir redis-cluster/7007 && sed 's/7006/7007/g' redis-cluster/7006/redis.conf > redis-cluster/7007/redis.conf

# 2. 启动新节点
redis-server redis-cluster/7006/redis.conf
redis-server redis-cluster/7007/redis.conf

# 3. 添加主节点到集群
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 4. 添加从节点并指定主节点
# 先查询7006的节点ID
redis-cli -p 7006 cluster nodes | grep myself
# 输出示例: d3f6c1f... 127.0.0.1:7006@17006 myself,master - 0 0 0 connected

redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 \
--cluster-slave --cluster-master-id d3f6c1f...

# 5. 重新分配槽位 (迁移16384/4≈4096个槽)
redis-cli --cluster reshard 127.0.0.1:7000

# 交互提示:
How many slots do you want to move? 4096
What is the receiving node ID? [输入7006的节点ID]
Source node 1: all

7、集群缩容

# 1. 迁移待删除主节点槽位到其他主节点
redis-cli --cluster reshard 127.0.0.1:7000 \
--cluster-from d3f6c1f... \  # 待删除节点ID
--cluster-to 5f9d1a2... \    # 接收槽位的节点ID
--cluster-slots 1365 \        # 迁移槽位数
--cluster-yes

# 重复直到所有槽位移出 (需执行多次)

# 2. 移除空主节点
redis-cli --cluster del-node 127.0.0.1:7000 d3f6c1f...

# 3. 移除从节点
redis-cli --cluster del-node 127.0.0.1:7000 7007节点ID

8、客户端连接

Maven 依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.4.3</version>
</dependency>

Java 连接代码

import redis.clients.jedis.*;
import redis.clients.jedis.resps.ClusterNode;
import java.util.*;

public class RedisClusterDemo {
    private static final int CONN_TIMEOUT = 2000;
    private static final int SO_TIMEOUT = 2000;
    private static final int MAX_ATTEMPTS = 3;

    public static void main(String[] args) {
        // 1. 配置集群节点
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("127.0.0.1", 7000));
        nodes.add(new HostAndPort("127.0.0.1", 7001));
        nodes.add(new HostAndPort("127.0.0.1", 7002));
        // 添加所有节点地址...

        // 2. 创建集群连接
        JedisClusterConfig config = new DefaultJedisClientConfig.Builder()
            .connectionTimeoutMs(CONN_TIMEOUT)
            .socketTimeoutMs(SO_TIMEOUT)
            .build();

        try (JedisCluster jedisCluster = new JedisCluster(nodes, config, MAX_ATTEMPTS)) {
            
            // 3. 集群信息检查
            System.out.println("=== Cluster Info ===");
            System.out.println(jedisCluster.clusterInfo());
            
            // 4. 键操作 (自动路由)
            jedisCluster.set("user:1001", "Alice");
            System.out.println("GET user:1001: " + jedisCluster.get("user:1001"));
            
            // 5. 使用HashTag确保多键在同一槽位
            jedisCluster.set("{order}:1001", "Pending");
            jedisCluster.set("{order}:1002", "Shipped");
            
            // 6. Pipeline批量操作 (需相同槽位)
            Pipeline pipeline = jedisCluster.pipelined();
            pipeline.set("counter", "0");
            pipeline.incr("counter");
            pipeline.incr("counter");
            List<Object> results = pipeline.syncAndReturnAll();
            System.out.println("Pipeline results: " + results);
            
            // 7. 直接访问特定节点
            Map<String, ConnectionPool> nodesMap = jedisCluster.getClusterNodes();
            try (Jedis jedis = nodesMap.get("127.0.0.1:7000").getResource()) {
                System.out.println("Node 7000 keys: " + jedis.keys("*"));
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

9、适用场景 vs 哨兵模式

场景集群模式哨兵模式
数据量> 100GB< 100GB
写并发> 5万 QPS< 5万 QPS
扩展需求需水平扩展仅需高可用
多键操作需槽位规划无限制
运维复杂度较高较低

根据 CAP 理论,Redis 集群优先保证 AP(可用性+分区容忍性),通过异步复制牺牲部分一致性。

四、代理模式

代理模式的核心目标是为Redis集群提供统一的入口,解决客户端分片的复杂性,并实现负载均衡、高可用等特性。

1、代理模式核心价值

  • 统一入口:为客户端提供单一访问端点

  • 协议兼容:支持标准Redis协议,客户端无需修改

  • 透明分片:自动处理数据分片逻辑

  • 高可用保障:内置故障检测与转移

  • 运维简化:节点变更对客户端透明

2、主流代理方案对比

特性TwemproxyCodisPredixyRedis Cerberus
开发语言CGoC++C
动态扩缩容
数据迁移手动自动依赖后端自动
读写分离
多集群支持
管理界面
生产成熟度★★★★☆★★★★★★★★★☆★★★☆☆
最新维护停止维护活跃活跃活跃

3、Twemproxy (nutcracker)

(1)架构原理

Client
Twemproxy
Redis1
Redis2
RedisN

(2)核心特性

  • 轻量级代理:单线程事件驱动模型

  • 分片算法

    • 一致性哈希(ketama)

    • 取模分片(modula)

  • 故障处理

    • 自动摘除故障节点

    • 手动恢复后需重新添加

(3)配置示例

alpha:
  listen: 127.0.0.1:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  server_retry_timeout: 30000
  server_failure_limit: 3
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6380:1

(4)致命缺陷

  • 节点变更需重启:扩缩容导致连接中断
  • 无数据迁移能力:需手动resharding
  • 单点瓶颈:单线程模型限制性能扩展

4、Codis

(1)架构全景

Client
CodisProxy
CodisDashboard
Zookeeper/Etcd
Group1
Group2
RedisMaster1
RedisSlave1
RedisMaster2
RedisSlave2

(2)核心组件

  • Codis Proxy:无状态代理,支持水平扩展

  • Codis Dashboard:集群管理中枢

  • Codis Group:Redis实例组(1主N从)

  • Storage:元数据存储(Zookeeper/Etcd)

(3)核心优势

  1. 动态扩缩容

    # 添加新Group
    codis-admin --dashboard=ADDR --create-group --gid=3
    
    # 数据迁移
    codis-admin --reshard --from=1 --to=3 --slots=100
    
  2. 自动故障转移

    • 集成Sentinel监控机制
    • 主节点故障自动提升从节点
  3. Web管理界面

    • 实时监控集群状态
    • 可视化数据迁移

(4)生产实践

# 典型部署架构
4x Codis Proxy(8核16G)
3x Codis Group(1主2从,64G内存)
1x Dashboard + 3x Zookeeper

5、Predixy

(1)架构亮点

读写分离
Client
Predixy
RedisMaster
RedisSlave
RedisCluster
SentinelCluster

(2)核心特性

  1. 多集群支持

    • 可同时代理标准主从、哨兵、集群模式
  2. 高性能设计

    • 多线程架构(C++实现)
    • 单实例支持15万+ QPS
  3. 智能读写分离

    # 配置读写规则
    ReadCommand {
        + get
        + hget
        + mget
        # 更多读命令...
    }
    
    WriteCommand {
        + set
        + hset
        + del
        # 更多写命令...
    }
    

(3)配置示例

conf

复制

下载

# 代理多个集群
Proxy {
    clusters {
        + cluster1 {
            type: cluster
            servers: ["127.0.0.1:7000", "127.0.0.1:7001"]
        }
        + cluster2 {
            type: sentinel
            master: mymaster
            sentinels: ["127.0.0.1:26379", "127.0.0.1:26380"]
        }
    }
}

# 连接池优化
WorkerThreads 16
ClientTimeout 300

6、Redis Cerberus(Twitter开源)

(1)创新架构

Raft协议
Client1
CerberusA
Client2
CerberusB
RedisMaster
RedisSlave

(2)核心价值

  1. 高可用代理
    • Active-Active双活架构
    • 代理层自身高可用
  2. 快速故障转移
    • 平均切换时间 < 2秒
    • 无需Sentinel参与
  3. 自动拓扑发现
    • 实时监控后端节点状态
    • 客户端零配置变更

(3)性能对比

场景直连RedisCerberus损耗率
SET操作 (QPS)120,000110,0008.3%
GET操作 (QPS)130,000118,0009.2%
故障转移时间-1.8s-

7、选型决策树

需要代理解决方案
是否需要动态扩缩容?
是否需要管理界面?
Codis
Predixy
是否需多集群支持?
是否要求代理层高可用?
Redis Cerberus
Twemproxy

8、生产环境建议

  1. 性能敏感型场景

    • Predixy(C++多线程)
    • 部署方案:4核/8G * 3实例
  2. 大规模动态集群

    • Codis + 专业运维团队

    • 关键配置:

      # Codis Proxy配置
      max_clients = 10000
      session_max_timeout = 30m
      session_max_bulk_size = 512mb
      
  3. 金融级高可用

    • Redis Cerberus双活部署
    • 网络要求:节点间RTT < 1ms
  4. 代理层监控关键指标

    • 连接数(client_connections)
    • 请求延迟(cmd_latency)
    • 错误率(cmd_errors)
    • 队列深度(request_queue)

最新趋势:云服务商托管代理(如AWS ElastiCache Proxy)逐渐成为企业首选,减少运维复杂度。

9、总结

场景推荐方案核心优势
传统分片Twemproxy极简稳定,低延迟
弹性伸缩集群Codis完整生态,可视化运维
混合架构Predixy多协议支持,高性能读写分离
零容忍故障Redis Cerberus亚秒级切换,代理层高可用

终极建议:对于新建系统,优先考虑云托管方案或官方Redis Cluster;遗留系统改造根据具体场景选择代理方案。

五、集群&代理模式

Redis 代理模式主要用于实现分片、高可用、负载均衡、协议转换、安全控制等功能,是构建大规模 Redis 应用架构的关键组件。

1、Redis 代理模式分类

(1)客户端分片(Client-side Sharding)

  • 原理:客户端库(如 Jedis、Lettuce)直接计算 Key 的分片位置,连接对应的 Redis 节点。
  • 优点:无代理层,性能高;架构简单。
  • 缺点:
    • 业务代码耦合分片逻辑,迁移困难。
    • 不支持动态扩缩容(需手动调整分片规则)。
    • 多语言支持成本高。
  • 典型方案:Redis Cluster 的客户端模式(需支持 Cluster 协议的客户端)。

(2)独立代理(Dedicated Proxy)

  • 原理:独立的中间件代理所有请求,负责路由、分片、聚合等。
  • 优点:
    • 业务代码无感知(透明分片)。
    • 支持动态扩缩容、读写分离、故障转移。
    • 统一控制入口(安全、监控)。
  • 缺点:增加网络跳转,性能略降(约 10-20%)。
  • 代表中间件:
    • Twemproxy (Nutcracker):Twitter 开源,轻量稳定,不支持动态扩缩容。
    • Codis:豌豆荚开源,支持动态扩缩容、Web 管理界面,需依赖 ZooKeeper/Etcd。
    • Predixy:支持 Redis Sentinel 和 Cluster,高性能,支持读写分离、多租户。
    • mcrouter:Meta 开源,支持 Redis/Memcached,适用于复杂路由场景。

(3)集群感知代理(Cluster-Aware Proxy)

  • 原理:代理自动感知 Redis Cluster 的拓扑变化,动态路由请求。
  • 优点:兼容 Redis Cluster 协议,无需额外维护分片信息。
  • 缺点:依赖 Redis Cluster 本身能力(如扩缩容复杂度)。
  • 代表方案:
    • Redis Cluster Proxy (官方实验版):提供单入口访问 Cluster。
    • Envoy Proxy:通过 Redis 过滤器支持 Cluster 路由。

(4)云服务商代理方案

  • 原理:云厂商托管的 Redis 服务内置代理(用户无感知)。
  • 优点:开箱即用,自动处理高可用、分片、备份。
  • 代表服务:
    • AWS ElastiCache (支持 Cluster 模式)
    • Google Memorystore
    • 阿里云 ApsaraDB for Redis

2、技术选型关键维度

维度选项对比
动态扩缩容Codis、云服务 > Redis Cluster > Twemproxy
性能客户端分片 > 独立代理(Predixy 性能较优)
复杂度独立代理 > 客户端分片(需业务集成)
高可用Redis Sentinel + Proxy / Redis Cluster / 云服务
协议兼容性大部分代理支持 Redis 5+,Codis/Predixy 对多命令支持更完善
监控与管理Codis 提供 Dashboard;云服务内置监控;Twemproxy 需自行集成 Prometheus
多语言支持代理模式天然支持多语言;客户端分片需各语言实现
安全代理可统一实现 TLS、ACL、IP 白名单

3、选型建议

场景方案优点
中小规模集群,追求简单稳定Redis Sentinel + Predixy支持自动故障转移、读写分离,Predixy 性能优异且配置简单。
大规模分片,需动态扩缩容Codis成熟的分片方案,支持无缝扩缩容,有可视化管控界面(需维护 ZooKeeper)
云环境部署云厂商托管服务免运维,自动处理高可用、备份、监控(如 AWS ElastiCache Cluster 模式)。
Kubernetes 环境Redis Cluster + Envoy Proxy通过 Envoy 的 Redis 过滤器实现流量治理,适合 Service Mesh 架构。
兼容 Redis Cluster 协议官方 Redis Cluster Proxy(待正式发布)未来标准方案,目前可用于测试环境。

4、性能优化建议

  • 连接池:代理层配置足够连接数(如 Predixy 的 worker_threads)。
  • Pipeline 支持:选择支持 Pipeline 的代理(如 Codis/Predixy 优化了 MGET/MSET)。
  • 批处理:避免大 Key 或跨节点事务(代理通常不支持 MULTI 跨分片)。
  • 监控指标:关注代理延迟(proxy_duration_us)、错误率(cmd_err_count)。

十、资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值