跳到主要内容

主从复制与 Sentinel 高可用

主从复制解决“数据有副本”和“读取可分担”;Sentinel 解决“主节点不可用时谁来切换”。它们仍只有一个主节点处理写入,不能解决单机容量上限。

完成本章后,你应该能解释主节点失联后副本如何追赶数据、为什么 Sentinel 至少部署 3 个,以及应用为什么不能写死主节点 IP。

1. 先看清拓扑

┌→ replica-1(默认只读)
应用 → master(写)┤
└→ replica-2(默认只读)

sentinel-1 ┐
sentinel-2 ├→ 监控 master/replica,并对故障切换投票
sentinel-3 ┘

复制默认是异步的:主节点向客户端返回成功时,写入可能尚未到达副本。因此主机突然损坏时仍可能丢失最近写入。WAIT 能等待副本确认,但它不是强一致事务,不能消除所有故障窗口。

2. 全量同步和增量同步

  1. 副本向主节点发送 PSYNC
  2. 没有共同复制历史时,主节点执行全量同步;
  3. 主节点生成 RDB,同时缓冲生成期间的新写入;
  4. 副本加载 RDB,再执行缓冲命令;
  5. 后续持续接收命令流;
  6. 短暂断线后,如果 backlog 仍包含缺失 offset,则增量同步,否则再次全量同步。
# 副本 redis.conf
replicaof 10.0.10.11 6379
masteruser replication
masterauth 替换为复制密码
replica-read-only yes
repl-backlog-size 256mb
repl-diskless-sync yes
redis-cli -h 10.0.10.11 INFO replication
redis-cli -h 10.0.10.12 ROLE
字段正常期望
role主节点 master,副本 slave/replica
master_link_status副本为 up
master_last_io_seconds_ago持续较小
主/副本 repl offset差距较小并能追平
repl_backlog_size覆盖常见网络中断窗口

backlog 可按“峰值写入字节率 × 可容忍断链时间 + 余量”估算。全量同步频繁时检查认证、网络、磁盘、大 key、副本输出缓冲和副本是否反复重启。

3. 动手搭建主从实验

docker network create redis-ha

docker run --detach --name redis-master --network redis-ha \
redis:7.4-alpine redis-server --appendonly yes

docker run --detach --name redis-replica-1 --network redis-ha \
redis:7.4-alpine redis-server --replicaof redis-master 6379

docker run --detach --name redis-replica-2 --network redis-ha \
redis:7.4-alpine redis-server --replicaof redis-master 6379
docker exec redis-master redis-cli SET ha:test 'from-master'
docker exec redis-replica-1 redis-cli GET ha:test
docker exec redis-replica-2 redis-cli INFO replication

尝试写副本:

docker exec redis-replica-1 redis-cli SET ha:test wrong-place

预期返回 READONLY。业务若读取副本,必须接受复制延迟导致的旧数据,并设计故障切换后的连接刷新。

4. Sentinel 如何判定和切换

  • SDOWN:单个 Sentinel 主观认为实例不可达;
  • ODOWN:达到 quorum 的 Sentinel 都认为主节点不可达;
  • leader:本轮负责执行 failover 的 Sentinel;
  • quorum:判定 ODOWN 的票数,不等于 leader 选举所需多数票。

至少部署 3 个 Sentinel,并跨故障域放置:

# sentinel.conf
port 26379
sentinel monitor mymaster 10.0.10.11 6379 2
sentinel auth-user mymaster sentinel
sentinel auth-pass mymaster 替换为密码
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
redis-cli -p 26379 SENTINEL master mymaster
redis-cli -p 26379 SENTINEL replicas mymaster
redis-cli -p 26379 SENTINEL sentinels mymaster
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

Sentinel 配置文件必须可写,因为它会保存发现的节点和切换结果。容器中把 sentinel.conf 只读挂载,会导致状态无法持久保存。

5. 故障演练步骤

  1. 查询并记录当前主地址;
  2. 从应用侧持续执行测试写入;
  3. 停止主节点并开始计时;
  4. 观察 +sdown+odown+elected-leader+switch-master 日志;
  5. 再查询主地址,确认已变化;
  6. 验证应用通过 Sentinel 发现新主并恢复写入;
  7. 恢复旧主,确认它成为新主的副本;
  8. 核对切换窗口的数据丢失或重复。

Sentinel 不切换的常见原因

  • 可通信 Sentinel 数量不足或 quorum 不合理;
  • Sentinel 与 Redis 的 ACL/密码配置错误;
  • 26379 或 Redis 端口被防火墙阻断;
  • 所有 Sentinel 与 Redis 位于同一故障主机;
  • 应用写死旧主地址,实际已切换但应用仍报错。

6. 清理实验

docker rm --force redis-master redis-replica-1 redis-replica-2
docker network rm redis-ha