02-Redis高可用与复制

#redis #高可用 #哨兵 #主从复制

这篇笔记讲什么
  • 主从复制:全量复制 + 增量复制,断线重连优先增量
  • 哨兵模式:监控、选主、通知,基于 Raft 投票选 Leader
  • 脑裂问题:用 min-slaves-to-write 限制主库写入条件
  • 选型:小规模用主从 + 哨兵,大规模用 Cluster

1. 主从复制

主库负责写,从库负责读,数据从主库同步到从库。这个和持久化配合使用,保证数据不丢。

1.1 全量复制

从库第一次连接主库,或者断线太久 backlog 追不上,触发全量复制:

从库发 psync → 主库执行 bgsave 生成 RDB → 发送 RDB → 从库加载
→ 主库把这期间的增量命令(replication buffer)也发过去

1.2 增量复制

正常同步时,主库把写命令写入 repl_backlog_buffer(环形缓冲区),从库持续读取执行。

断线重连后,只要偏移量还在 backlog 范围内,就走增量同步,不用全量。

repl-backlog-size 1mb  # 根据写入速度 × 预估断线时间 × 2 来设置

1.3 主从从模式

从库多了,主库压力大。可以让从库再挂从库,分散压力:

主库 → 从库1 → 从库2、从库3

2. 哨兵模式

哨兵负责三件事:监控、选主、通知

2.1 监控

哨兵周期性地给主从库发 PING 命令,检测是否在线。

单个哨兵可能误判,所以用多个哨兵组成集群一起判断。

2.2 哨兵集群怎么组建

基于 pub/sub 机制

多个哨兵都连到主库,订阅 sentinel:hello 频道,通过这个频道互相知道对方的 IP 和端口,然后建立连接。

哨兵还会向主库发 INFO 命令,拿到从库列表,再和每个从库建立连接。

2.3 选主流程

分两步:筛选 + 打分

筛选条件

  1. 从库当前是否在线
  2. 历史网络连接状态好不好

打分规则(按优先级):

优先级 规则 说明
1 slave-priority 从库优先级配置,值越小优先级越高
2 slave_repl_offset 复制进度,offset 越大得分越高
3 从库 ID ID 小的得分高

先比优先级,一样再比复制进度,还一样就比 ID。

2.4 投票机制

基于 Raft 协议 进行选举。获得多数票(N/2+1)的哨兵成为 Leader,由它执行故障转移。

2.5 通知

选好新主库后:

  1. 通知其他从库执行 replicaof,连到新主库
  2. 通知客户端,把请求发到新主库

3. 脑裂问题

什么是脑裂:主库网络抖动,哨兵判定它下线并选出新主库,但原主库其实还活着,这时候出现两个主库。

客户端还在往原主库写数据,等原主库重新加入集群变成从库时,这些数据就丢了。

3.1 怎么解决

调整三个参数:

参数 含义
min-slaves-to-write 主库能写入的最少从库数量
min-slaves-max-lag 从库给主库发 ACK 的最大延迟(秒)
down-after-milliseconds 多久没响应判定下线(毫秒)

举个例子:

min-slaves-to-write = 1
min-slaves-max-lag = 10s
down-after-milliseconds = 10s

主库卡住 15s → 哨兵判定下线 → 开始主从切换。同时,因为主库卡了 15s,没有从库能在 10s 内完成数据复制,所以主库拒绝写入。

这样切换完成后,只有新主库能接收请求,不会丢数据。

4. 三种部署方式怎么选

主从复制 哨兵模式 Cluster
高可用 无自动故障转移 自动故障转移 自动故障转移
数据分片
横向扩展
适合数据量 < 10GB < 10GB 不限
适合 QPS < 10 万 < 10 万 不限
复杂度

小规模用主从 + 哨兵,数据量大或 QPS 高就上 Cluster。

5. 缓冲区

主从复制涉及几种缓冲区:

缓冲区 用途 能调大小吗
客户端输入缓冲区 存客户端发来的命令 不能
客户端输出缓冲区 存返回给客户端的数据
主从复制缓冲区 主库发给从库的数据
复制积压缓冲区 环形缓冲区,存增量同步的命令

所有缓冲区溢出的处理方式都一样:直接关闭连接。

配置方式:

# 普通客户端:硬限制 0,软限制 64MB/60s
client-output-buffer-limit normal 0 0 0

# 从库客户端:硬限制 256MB,软限制 64MB/60s
client-output-buffer-limit replica 256mb 64mb 60

# 发布订阅:硬限制 32MB,软限制 8MB/60s
client-output-buffer-limit pubsub 32mb 8mb 60