前言
在前面的文章中,我们拆解了Redis的数据结构、内存管理和持久化。但还有一个根本性问题没有解决:单机Redis存在单点故障------机器宕机,整个服务不可用。
这就是主从复制和哨兵机制要解决的问题。面试中,这两个概念经常被连续追问:
"主从复制的全量复制和部分复制有什么区别?"
"哨兵是怎么发现主库故障的?主观下线和客观下线有什么区别?"
"哨兵集群是怎么选主的?"
"哨兵和Cluster有什么区别?"
本文从主从复制的原理出发,拆解哨兵机制的工作原理,最后落到生产环境的高可用配置方案。
本文核心问题:
- 主从复制的工作原理是什么?全量复制和部分复制有什么区别?
- 主从延迟是怎么产生的?如何处理?
- 哨兵是什么?它是怎么发现主库故障的?
- 主观下线和客观下线有什么区别?
- 哨兵集群是怎么选主的?选主逻辑是什么?
- 哨兵和Cluster各自的适用场景是什么?
- 秒杀项目中的Redis高可用是怎么配置的?
读完本文,你将对Redis的高可用机制拥有从原理到配置的完整理解。
一、主从复制------数据冗余的基础
疑问:为什么需要主从复制?主库宕机了怎么办?
回答:主从复制是Redis高可用的基础。主库负责写,从库负责读。主库宕机后,从库可以接管,保证服务不中断。
1.1 主从复制的基本架构
┌──────────┐ 复制 ┌──────────┐
│ 主库 │─────────────→│ 从库 │
│ (写) │ │ (读) │
└──────────┘ └──────────┘
│
│ 复制
↓
┌──────────┐
│ 从库 │
│ (读) │
└──────────┘
读写分离能降低主库压力------主库专注处理写操作,读操作分摊到多个从库上。同时从库作为数据备份,主库宕机时可快速切换到从库恢复服务。
1.2 全量复制------初次建立连接
从库第一次连接主库或长时间断开后重新连接时,需要全量同步------主库执行bgsave生成RDB文件发送给从库,从库清空自身数据后加载这个RDB,再追加上同步期间的增量命令。
全量复制流程:
1. 从库向主库发送SYNC命令
2. 主库执行bgsave → 生成RDB快照
3. 主库将RDB文件发送给从库
4. 主库在发送RDB期间的写操作 → 记录到复制缓冲区
5. 从库接收RDB → 清空自身数据 → 加载RDB
6. 主库发送复制缓冲区中的增量命令 → 从库执行
7. 全量复制完成 → 进入增量复制阶段
全量复制的开销:主库bgsave消耗CPU和内存(Copy-On-Write期间被修改的页要额外复制),RDB文件传输占用网络带宽,从库清空数据后加载RDB需要时间。大内存实例的全量同步可能持续数分钟,期间主从之间没有实时数据同步。
1.3 部分复制------断线重连
Redis 2.8+支持部分复制------从库短暂断开后重连,如果断连期间的增量还在主库的复制缓冲区中,只同步缺失的这一小段增量,不需要全量复制。
部分复制的条件:
1. 从库记录了上次同步的主库run_id
2. 主库的run_id没有改变(没有重启或切换)
3. 从库请求的偏移量还在主库的复制缓冲区中
不满足任何一条 → 退化为全量复制
部分复制的核心:主库维护一个复制缓冲区(默认1MB),记录最近的写命令。从库重连时告诉主库"我上次收到偏移量X",主库检查X是否还在缓冲区中------如果在,直接发送X之后的所有增量;如果不在,只能触发全量复制。
1.4 主从延迟
主从复制是异步的------主库处理完写操作后不等待从库确认就返回客户端。从库可能落后主库几十毫秒到几秒。产生原因:主库并发写入,从库单线程回放命令;网络带宽不足时RDB传输拖慢同步;从库硬件比主库差,回放速度跟不上。
处理方式:关键业务(下单、支付)直接读主库;可接受延迟的查询(列表、详情)走从库;延迟超标时告警并自动切换读流量回主库。
二、哨兵机制------自动故障转移
疑问:主库宕机了,怎么自动切换到从库?
回答:哨兵(Sentinel)就是干这件事的------它监控Redis节点的健康状态,主库故障时自动执行故障转移。
2.1 哨兵的四个核心职责
| 职责 | 做什么 | 如何实现 |
|---|---|---|
| 监控 | 检查主从节点是否正常运行 | 定期发送PING命令 |
| 通知 | 节点故障时通过Pub/Sub通知客户端 | 发布订阅消息 |
| 自动故障转移 | 主库故障时选择从库升级为新主库 | 选主算法(多个哨兵协商) |
| 配置提供者 | 客户端询问哨兵获取当前主库地址 | 哨兵返回最新主库IP |
2.2 主观下线 vs 客观下线
主观下线:单个哨兵判断某个节点不可达。当哨兵发送的PING在指定时间内没有收到有效回复时,这个哨兵将节点标记为主观下线。但主观下线可能是网络分区导致的误判------如果只有这一个哨兵的网络出了问题,主库实际还在正常运行。
客观下线:多个哨兵共同判断主库是否真的故障。一个哨兵发现主库主管下线后,询问其他哨兵是否也认为主库不可达。当法定人数(quorum)的哨兵都确认后,主库被标记为客观下线------确认主库真正故障,触发故障转移。
配置:quorum = 2(至少2个哨兵同意)
场景:哨兵A发现主库不可达 → 主观下线
哨兵A询问哨兵B:"你觉得主库挂了吗?" → 哨兵B回答"是的"
哨兵A询问哨兵C:→ 哨兵C回答"我的网络也连不上"
2个哨兵确认 → 客观下线 → 触发故障转移
2.3 哨兵集群的选主过程
客观下线确认后,哨兵集群用Raft算法选举出一个哨兵作为本次故障转移的leader。选主条件基于从库与主库的同步偏移量------最接近原主库的从库优先;多个从库偏移量相同时,优先级高的从库(slave-priority值小)优先;优先级也相同时,run_id字母序最小的从库优先。leader哨兵执行故障转移:将选中的从库升级为主库,向其他从库发送"新主库在哪"的指令,通知客户端主库地址变更。
三、哨兵 vs Cluster
| 维度 | 哨兵(Sentinel) | Cluster |
|---|---|---|
| 数据分片 | 不涉及(一主多从模式下,所有节点存完整数据) | 数据按哈希槽分片分布到多个主节点 |
| 故障转移 | 自动,哨兵协作选主后通知所有从库和客户端 | 自动,Gossip协议在集群内部确认故障并投票选主 |
| 适用规模 | 中小规模,数据量可存入单机内存 | 大规模,单机无法容纳全部数据 |
| 复杂度 | 较低 | 较高,客户端需要处理MOVED和ASK重定向 |
| 客户端要求 | 需要知道哨兵地址或支持Sentinel感知 | 需要支持Cluster协议或使用Proxy组件 |
选择规则:数据能存入单机内存+读多写少→哨兵,简单够用;数据量超过单机内存或写入量大→Cluster,水平扩展。
四、秒杀项目中的配置
conf
# sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2 # 2个哨兵同意即可客观下线
sentinel down-after-milliseconds mymaster 5000 # 5秒不可达即主观下线
sentinel failover-timeout mymaster 10000 # 故障转移超时10秒
sentinel parallel-syncs mymaster 1 # 故障转移后,一次只允许一个从库做全量复制
选型考量:秒杀系统的库存和缓存全存在Redis中,但数据量在2GB以内,单机能容纳。一主两从+三名哨兵分布在三台服务器上,解决了单点故障。不需要Cluster的分片能力,也不需要处理MOVED重定向的客户端兼容性------哨兵方案刚好够用。
故障演练的发现:手动kill主库进程后,哨兵在5秒主观下线+quorum投票+选主过程中共耗时约8秒恢复服务。这8秒的恢复空窗内所有请求被Sentinel限流组件兜底------返回"系统繁忙",不强行操作数据。故障转移完成后新主库接管写操作,从库自动切换到新主库继续同步。
五、面试中这样回答
面试官:"哨兵是怎么工作的?"
回答框架:
"哨兵有四个核心职责:监控、通知、自动故障转移、配置提供。它定期PING主从节点,发现主库不可达时标记为主观下线,然后询问其他哨兵确认------达到quorum法定人数后标记为客观下线。多个哨兵用类似Raft的方式选举出leader,由leader在主库的从库中选一个数据最新的升级为新主库,通知其他从库和新主库建立复制关系,并通知客户端更新连接地址。"
面试官:"主观下线和客观下线有什么区别?"
回答:
"主观下线是单个哨兵的判断------自己连不上主库。但可能是网络分区导致的误判。客观下线是多个哨兵协商的结果------quorum个哨兵都认为主库不可达。只有客观下线才会触发故障转移,这是为了防止单哨兵误判导致不必要的切换、甚至出现两个主库同时接受写入的split-brain。"
总结
- 主从复制是数据冗余的基础:全量复制用于首次同步,部分复制用于断线重连。复制缓冲区的大小决定是否退化为全量复制
- 主从延迟是异步复制的固有代价:关键业务读主库,非关键业务读从库。延迟超标时自动切回主库
- 哨兵负责高可用:主观下线是单哨兵判断,客观下线是法定人数确认。只有客观下线才触发故障转移,防止误判
- 哨兵集群内部选举leader执行故障转移,选主逻辑从数据完整性、配置优先级、run_id三个维度逐层判断
- 哨兵 vs Cluster是规模和复杂度的选择:数据量在单机内存内选哨兵,超过单机内存选Cluster
- 秒杀项目用哨兵方案:数据量小、读写比例高、不需要分片的经验丰富度和容错特性。一主两从+三哨兵,主库宕机后几秒内自动恢复服务
下一篇预告:Redis原理(六)------Redis Cluster,分布式缓存的进阶方案。拆解哈希槽的数据分片原理,MOVED和ASK重定向的区别,以及Cluster模式下的故障转移和局限性。