Redis 集群 Cluster

单机 Redis 的容量有上限:数据涨到几十 GB 后,复制、持久化、恢复都会变慢,单点故障还会拖垮整个业务。Cluster 是 Redis 原生的数据分片方案:把 16384 个哈希槽分给多个主节点,读写自动路由到对应节点,既能横向扩容,又靠分片内的主从副本提供高可用。

分片原理:槽与哈希

Cluster 槽分片与三主三从 Cluster 按 key 的哈希值把数据摊到 16384 个槽(slot),每个主节点负责一段槽区间:

槽号 = CRC16(key) % 16384

想让几个 key 强制同槽,用 hash tag:只对花括号内内容哈希,如 {u}:1 与 {u}:2 的哈希对象都是 u,必然同槽,便于执行多键命令。

开启集群模式

每个节点都在 redis.conf 中开启集群模式。除 6379 客户端端口外,还要保证 16379(客户端端口 +10000)的集群总线端口互通:

cluster-enabled yes              # 开启集群模式
cluster-config-file nodes.conf   # 自动保存节点与槽位信息
cluster-node-timeout 15000       # 节点间心跳超时(毫秒)
appendonly yes                   # 建议同时开启持久化

创建集群

推荐最小规模 3 主 3 从。先分别启动 6 个集群节点,再一次性拉起,--cluster-replicas 1 表示每个主节点配 1 个从节点:

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
# 输出节选:>>> Performing hash slots allocation on 6 nodes...
#          Master[0] -> Slots 0 - 5460
#          [OK] All 16384 slots covered

客户端访问与 MOVED/ASK

不带 -c 直连某节点,操作落在别的槽会收到 MOVED 错误,提示该 key 归谁管;加 -c 后客户端自动跟随重定向再发一次,交互无感:

127.0.0.1:7000> SET foo bar
# 输出:(error) MOVED 12182 127.0.0.1:7002
127.0.0.1:7000> SET foo bar     # redis-cli -c 集群模式
# 输出:-> Redirected to slot [12182] located at 127.0.0.1:7002
#       OK

MOVED 表示槽已永久迁走,客户端应更新本地槽映射后直连目标;ASK 只在槽迁移期间出现,仅当次请求先发 ASKING 再访问目标节点,不必更新映射。

多键命令的限制

MSET、MGET、事务、Lua 脚本等涉及多个 key 的命令要求所有 key 同槽,否则报 CROSSSLOT,用 hash tag 可规避:

127.0.0.1:7000> MSET user:1 a user:2 b   # 分属不同槽
# 输出:(error) CROSSSLOT Keys in request don't hash to the same slot
127.0.0.1:7000> MSET {u}:1 a {u}:2 b
# 输出:OK

节点管理:扩容与缩容

扩容先 add-node 加入新主节点,再 reshard 迁槽(数据随槽搬移),槽位不均用 rebalance 自动均衡;缩容则先把槽迁光,再 del-node 移除,日常用 check 巡检:

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
# 输出节选:[OK] New node added correctly
redis-cli --cluster reshard 127.0.0.1:7000 \
  --cluster-from <源节点ID> --cluster-to <目标节点ID> --cluster-slots 4096 --cluster-yes
redis-cli --cluster rebalance 127.0.0.1:7000      # 输出节选:Moving 136 slots
redis-cli --cluster del-node 127.0.0.1:7000 <待删节点ID>
# 输出节选:[OK] Node ... removed

故障转移

每个分片都是“一主一从/多从”,主节点宕机后从节点发起选举自动晋升,也可在从节点手动触发:

127.0.0.1:7003> CLUSTER FAILOVER    # 优雅切换,主从互换
# 输出:OK

同分片主从全部宕机时槽位不可用;cluster-require-full-coverage 默认 yes,此时整个集群拒绝服务,避免读到残缺数据,可用 CLUSTER INFO 查看 cluster_state。

哨兵 vs 集群选型

维度哨兵方案Cluster
数据分布不分片,单主写16384 槽水平分片
扩展性只能加从库扩读加节点迁槽即扩读写
高可用哨兵进程自动切换分片内从节点自动晋升
适用场景容量够、只求高可用数据量大或写并发高

小结:Cluster 用 CRC16(key) % 16384 把数据分到多主节点,创建建议 3 主 3 从起步;扩容走 add-node 加 reshard,故障靠分片内 failover,缩容先迁光槽再 del-node。数据量不大用哨兵更省心,需要水平扩展再上 Cluster。

笔记加载中…