Redis 主从复制与 Sentinel 原理
→ 返回 Redis
主从复制解决数据副本和读扩展,Sentinel 在主从之上增加监控、通知与自动故障转移。二者都不提供强同步提交:Redis 默认复制是异步的,主节点确认写入时从节点可能还没收到。
部署演进
| 形态 | 容量 | 高可用 | 适用 |
|---|---|---|---|
| 单机 | 受单机内存限制 | 无 | 开发、可丢缓存 |
| 主从 | 读扩展 | 手动切换 | 读多写少 |
| Sentinel | 读扩展 | 自动 failover | 中小规模、不需水平分片 |
| Cluster | 水平分片 | 分片 + 副本 | 见 Cluster |
复制流中的 replid 与 offset
每个主节点维护复制历史标识 replid,复制流每产生一个字节都会推进 offset。二元组:
(replication ID, replication offset)可以标识数据集复制历史中的一个位置。从节点记录自己处理到的 replid 和 offset,重连时通过:
PSYNC <replid> <offset>请求续传。主节点维护固定大小的环形 replication backlog;即使暂时没有从节点,复制流也可以在 backlog 开启时保留一段历史。
主节点复制流 offset ───────────────────────────────►
[ replication backlog 环形窗口 ]
▲
replica offset如果从节点所缺的数据仍在 backlog 中,且 replid 属于主节点认可的历史,主节点返回 CONTINUE 并只补发缺失字节;否则返回 FULLRESYNC,执行全量同步。
故障切换后,新主节点会保留上一段复制历史作为辅助 replid(可在 INFO replication 看到 master_replid2 等字段),让原主或其他从节点有机会部分同步,而不是全部重新传 RDB。
全量同步
Replica Primary
│──── PSYNC replid offset ─────►│
│◄──── FULLRESYNC new-id off ───│
│ ├─ fork / BGSAVE
│ ├─ 同时缓存新写命令
│◄──────── RDB 快照 ────────────│
├─ 清空旧数据并加载 RDB │
│◄──── 快照期间的增量命令 ──────│
│◄──── 后续实时命令流 ──────────│步骤:
- 从节点建立连接,认证并交换能力、端口等信息;
- 从节点发送
PSYNC;无法部分同步时进入FULLRESYNC; - 主节点后台生成 RDB,同时把新写入保存在复制客户端缓冲区;
- 主节点发送 RDB,从节点接收并加载;
- 主节点发送生成快照期间积累的写命令,随后进入稳定的命令流复制。
主节点可采用磁盘式 RDB,也可配置 diskless replication 通过 socket 直接把快照流发送给从节点。无盘方式减少磁盘中转,但仍有 fork、网络和 COW 成本。
多个从节点同时请求全量同步时,主节点在条件允许时会复用一次后台快照;批量重启、网络抖动或 backlog 太小仍可能造成全量同步风暴。
部分同步为什么会失败
| 原因 | 结果与处理 |
|---|---|
| 断线太久,缺失字节已被环形 backlog 覆盖 | 全量同步;增大 repl-backlog-size |
| replid 不属于当前或可追溯的复制历史 | 全量同步 |
| 主节点重启且复制历史无法衔接 | 全量同步;重要节点启用合适持久化 |
| 从节点首次连接 | 没有可续传位置,执行全量同步 |
backlog 大小应覆盖“峰值写入字节速率 × 期望容忍的断线时间”,并保留余量。例如写复制流 20 MB/s,希望容忍 60 秒断线,理论下限约 1.2 GB,而不是只按 key 数估算。
复制一致性与安全边界
Redis 默认异步复制:
客户端写入 → 主节点执行并返回 → 命令异步发往从节点因此存在:
- 主节点已返回成功、命令尚未到达从节点时宕机,故障切换后该写入丢失;
- 从库读取可能落后,出现“刚写完却读不到”;
- 网络分区中的旧主若仍对外服务,可能形成脑裂写入。
WAIT numreplicas timeout 可以等待指定数量副本确认到达当前 offset,缩小丢数据概率,但它不是分布式事务或严格线性一致提交;超时、故障窗口和持久化策略仍需考虑。
min-replicas-to-write 1
min-replicas-max-lag 10
replica-read-only yes前两项可在可用副本不足时让主节点拒绝写,降低脑裂旧主持续接单的风险,代价是网络异常时牺牲可用性。
Sentinel 故障检测与切换
建议至少 3 个独立 Sentinel,并让它们跨故障域部署。Sentinel 持续监控主从节点和其他 Sentinel:
PING 超时
▼
SDOWN(某个 Sentinel 主观下线)
▼ 向其他 Sentinel 询问,达到 quorum
ODOWN(主节点客观下线)
▼
Sentinel 竞选本轮故障转移 Leader
▼
选择从节点并执行 SLAVEOF NO ONE
▼
其余从节点改为复制新主,客户端发现新主quorum 是判定 ODOWN 所需的 Sentinel 同意数;真正授权故障转移还需要 Sentinel 多数派。两者不是同一个概念,所以“quorum 配 1”并不代表单 Sentinel 永远能完成切换。
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1新主选择考虑因素
Sentinel 会过滤已下线、长时间断联或配置为不参与提升的从节点,再综合 replica priority、复制进度和运行 ID 等因素选择。通常希望选择数据较新且优先级合适的副本,而不是简单随机选择。
客户端必须支持 Sentinel
客户端不能把旧主地址永久写死。Lettuce、Jedis 或 Redisson 的 Sentinel 模式会向 Sentinel 查询当前主节点,并在切换后重建连接。故障转移窗口内请求仍可能失败,业务端需要有限重试、幂等和熔断,避免无限重试风暴。
诊断与容量规划
INFO replication
ROLE
WAIT 1 1000重点指标:
master_repl_offset与从节点 offset 差值;master_replid/master_replid2;repl_backlog_size/repl_backlog_histlen;master_link_status、master_last_io_seconds_ago;- 全量同步次数、网络吞吐、RDB fork/COW 和从节点加载耗时。
面试结论
Redis 通过 replid + offset 标识复制历史,从节点用 PSYNC 请求续传;所缺字节仍在 replication backlog 中就部分同步,否则主节点生成 RDB 做全量同步,再补发期间积累的命令。复制默认异步,Sentinel 负责检测、选举和主从切换,但不能消除复制窗口的数据丢失,需结合
min-replicas-*、WAIT、持久化、幂等与备份设计。