摘要:单机 Redis 再强也有天花板。本文不堆砌概念,而是通过真实的"秒杀崩盘"故事,带你从零构建 Redis 主从、哨兵到 Cluster 分片集群,解决高并发下的数据一致性与可用性难题。
💥 真实故事:那个被"秒杀"干崩的夜晚
那年我负责电商大促,自信满满地把 Redis 升级到 16核64G,心想这配置够牛逼了吧?结果零点秒杀开始,CPU 直接飙到 100%,延迟从几毫秒飙升到 1.2 秒。更要命的是,流量稍降后,Redis 居然 OOM 崩溃了------因为 RDB fork 时内存翻倍,瞬间撑爆了机器。
那晚我通宵做了两件事:关掉 RDB,开始研究集群。后来我才明白,单机 Redis 就像一个超级快递员,跑得再快也送不完全城的包裹。想要高可用,必须搞"团队作战"。
今天这篇,我将从 Java 开发实战角度,把 Redis 集群的三种方案掰开揉碎。不管你是准备面试,还是生产环境落地,看完心里都有底了。
🤔 一、为什么单机 Redis "不够用"?
在真实生产环境中,单机 Redis 往往面临"三座大山":
- 💣 单点故障:机器一挂,缓存雪崩,数据库瞬间被"打死"。
- 🧱 内存瓶颈 :数据量大时,RDB
fork需要额外内存,加上碎片,64G 机器可能存 20G 数据就 OOM。 - 🐢 写瓶颈:主库只有一个,所有写请求串行处理。真实线上,单机稳定 2-3 万 QPS 就不错了,超过即延迟飙升。
结论:集群不是"要不要"的问题,而是"什么时候上"的问题。
🛠️ 二、主从复制:最简单的"备胎模式"
2.1 核心架构
场景 :读多写少,需要数据备份。 原理:一主多从,主库写,从库读,异步同步数据。
bash
# 配置从库(Redis 5 以前用 SLAVEOF,以后推荐 REPLICAOF)
127.0.0.1:6380> REPLICAOF 192.168.1.100 6379
2.2 底层原理(面试必问)
主从复制分为四个阶段:
- 建立连接:从库发起 Socket 连接。
- 全量复制 :主库
fork子进程生成 RDB 发送。 - 增量复制 :发送全量期间产生的写命令(存于
repl_backlog_buffer)。 - 实时同步:主库每写一个命令,异步发给从库。
⚠️ 避坑指南:Fork 的代价
全量复制时,如果主库内存 20G,
fork可能耗时 2-3 秒,这期间主库会阻塞 无法处理请求。生产环境千万别在高峰期加从库!
2.3 三个"小麻烦"
-
主从延迟:异步复制导致读到旧数据。
- 监控命令 :
INFO replication(对比master_repl_offset和slave_repl_offset)
- 监控命令 :
-
断连成本高 :断连时间长导致
repl_backlog溢出,触发全量复制(又是fork)。 -
无自动切换:主库挂了,从库只能傻等,需要手动干预。
🚓 三、哨兵模式:自动"选老大"的机制
3.1 哨兵在干什么?
哨兵(Sentinel)是一组独立进程,负责监控主从节点,并在主库挂掉时自动完成故障转移。
3.2 核心逻辑:主观 vs 客观下线
-
主观下线 (
sdown) :单个哨兵认为主库挂了。 -
客观下线 (
odown) :超过quorum(法定数量)的哨兵都认为挂了,才触发切换。- 目的:防止网络分区误判(例如哨兵 A 自己网络断了,误以为主库挂了)。
3.3 故障转移配置示例
conf
# sentinel.conf
sentinel monitor mymaster 192.168.1.100 6379 2
# 2 表示至少 2 个哨兵同意才算客观下线
sentinel down-after-milliseconds mymaster 30000
# 30秒无响应认为挂了
3.4 实际痛点
虽然解决了"自动切换"的问题,但写能力没有扩展 ,内存瓶颈依然存在。如果业务写入极猛或数据量巨大,哨兵也扛不住。
🌐 四、Redis Cluster:真正的"分布式"方案
4.1 分片原理:哈希槽 (Hash Slot)
Cluster 将数据分片存储,核心是 16384 个哈希槽。
- 计算公式 :
slot = CRC16(key) % 16384 - 场景:比如节点 A 负责 0-5000,节点 B 负责 5001-10000。
⚠️ 避坑指南:Hash Tag
Cluster 不支持跨槽事务。如果想用
MSET操作多个 Key,必须让它们落在同一个槽。
解决方案 :使用Hash Tag,只对{}内的内容做哈希。
text
{user:1001}.name
{user:1001}.age
# 这两个 Key 会落在同一个槽
4.2 手把手搭建集群 (3主3从)
1. 配置文件 (redis-7000.conf)
conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
2. 创建集群
bash
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
# --cluster-replicas 1 表示每个主库配 1 个从库
4.3 客户端连接与路由
客户端(如 JedisCluster)会缓存 Key 到节点的映射。如果连错节点,节点会返回 MOVED 错误,客户端自动重定向。
4.4 故障转移
Cluster 使用 Gossip 协议,节点间互相通信。当半数以上主节点认为某主节点挂了(fail),其从节点会自动升级为主节点。
⚠️ 避坑指南:大规模迁移
生产环境做
reshard迁移几千万 Key 时,期间集群性能可能下降。建议在业务低峰期操作,或采用"双写 + 逐步切流"策略。
📊 五、三种方案怎么选?一表看懂
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 主从复制 | 读多写少、数据量小 | 配置简单、读写分离 | 无自动故障转移、写瓶颈 |
| 哨兵模式 | 需要高可用、数据量中等 | 自动故障转移 | 写和内存仍是瓶颈 |
| Cluster | 大数据量、高并发写入 | 线性扩展、高可用 | 配置复杂、不支持跨槽事务 |
简单决策树:
- 个人/低流量 -> 主从
- 公司内部系统 -> 哨兵
- 大型互联网/秒杀 -> Cluster
💼 六、面试官最爱问的"灵魂拷问"
Q1:主从复制是同步还是异步?
- A :默认是异步 的。主库写完就返回,不等从库。如果要求强一致,可用
WAIT命令,但会牺牲性能。
Q2:哨兵挂了大半,集群还能读写吗?
- A :能读写 。哨兵只负责监控。只要 Redis 主库活着,业务照常。但如果此时主库也挂了,因为哨兵不够数,无法切换,集群就真挂了。
Q3:Cluster 迁移过程中访问 Key 怎么办?
-
A:
- Key 没迁移:旧节点正常处理。
- Key 已迁移:旧节点返回
ASK错误,客户端需向新节点发ASKING命令再操作。
📝 七、写在最后
Redis 集群方案没有银弹。
-
别迷信最佳实践:有人用哨兵扛 100G 数据结果 OOM,有人上 Cluster 却因跨槽操作改代码改到崩溃。
-
建议:
- 先上主从:大多数项目主从+哨兵足够。
- 监控先行 :盯住
INFO replication、延迟和慢日志。 - 压测再上:别以为 Cluster 就一定快,跨节点访问延迟可能更高。
搞懂了这些,你就能从一个"会用 Redis"的工程师,变成一个"能让 Redis 为业务扛住一切"的工程师。
如果你觉得这篇文章帮你理清了思路,或者帮你面试多拿了一分,请点个赞支持一下!
也欢迎在评论区聊聊你遇到的 Redis "灵异事件",我们一起排雷!
📚 关注《卷毛的技术笔记》
👋 我是卷毛,一名热爱分享技术干货的后端工程师。
在这里,你将获得:
- 硬核实战:拒绝空谈,只讲生产环境能落地的架构方案。
- 避坑指南:我踩过的坑,帮你填平。
- 面试突击:大厂高频面试题深度解析。
关注我,带你少加班,多升职!