高可用

主从复制

主要优点:数据备份、读写分离,通常和哨兵模式结合使用。 Alt text 主服务器负责读写请求,从服务器默认只负责读请求
主节点在执行完写请求之后,将写命令同步到从节点,然后从节点再执行这条命令,保证和主节点的数据一致。

  1. 从节点向主节点发送 SYNC 命令,希望建立连接。
  2. 主节点回复 FULLRESYNC 命令给从节点,并且携带两个参数:主节点的runID和复制进度offset
  3. 主节点执行bgsave, 生成RDB文件,传输给从节点。(主节点生成RDB文件期间、传输RDB文件期间,还有从节点加载RDB文件期间,主节点会把新的写命令写入replication buffer中。)
  4. 从节点将RDB数据加载进内存;主节点把replication buffer中的命令发给从节点,让它执行。

主从节点在完成第一次同步后,就会维护一个TCP长连接。

配置

1
2
3
4
5
6
# 主节点配置
bind 0.0.0.0
port 6379

# 从节点配置
replicaof <master-ip> <master-port>

问题

如果向主节点请求全量复制的从节点太多,主节点就要fork出多个子进程来生成 RDB 文件,可能造成主节点阻塞
并且,传输多份 RDB 文件可能占用主节点的带宽。

解决:让某些从节点从其他从节点进行复制,而不是直接从主节点复制。这样可以减少主节点的直接压力。

增量复制

如果主节点和从节点的网络连接突然断开了,那么在他们重新建立连接的时候,就会发生增量复制
从节点会把 replication offset 携带在 PSYNC 命令中。
master_repl_offset标记主节点写到的位置,slave_repl_offse标记从节点读到的位置。
主节点在发送写命令给从节点的同时,还会把写命令发送给repl_backlog_buffer,这是一个专门用于增量复制的环形缓冲区,默认大小为 1MB。

发生增量复制时,主节点会根据两个 offset 判断从节点需要补充的数据是否在repl_backlog_buffer中。如果不在就得选择全量复制。
如果在,主节点就把repl_backlog_buffer中,从节点缺乏的那部分数据放入replication buffer,然后发给从节点。

主从数据不一致

原因:主从复制是异步进行的。主节点在处理完写请求并且返回时,不一定保证从节点已经执行完该写请求。

改进:Redis的Info Replication命令可以读取到master_repl_offset和slave_repl_offset,如果它们的差值大于某个阈值,则设置为让客户端不和该从节点连接。

哨兵模式

主要实现主从模式的自动故障恢复

判断宕机

哨兵每隔一秒向主节点和从节点发送 PING,如果在规定时间(down-after-milliseconds)内没有收到 PONG,则判断该节点主观下线
一般需要一个哨兵集群,当哨兵集群中超过某个阈值(quorum)的哨兵判断主节点为主观下线,则此时主节点为客观下线

故障转移

判断主节点为客观下线的从节点,成为候选者。候选者们互相投票,选出一个 leader。首先需要拿到半数以上的赞成票,其次票数要大于quorum。

接着,让原主节点的从节点修改复制目标为新主节点

将新主节点的 IP 地址和信息通过 pub/sub模式,发布给客户端。

继续监控旧主节点。当它重新上线时,把它设置为新主节点的从节点

选新主节点的过程:

  1. 排除断开连接次数太多的从节点,它们网络状态不好
  2. 按从节点的优先级选,slave-priority越低越好
  3. 若优先级一样,谁的 offset 最大就选谁
  4. 若 offset 也一样,选 ID 最小的从节点

哨兵leader

Sentinel 集群里的 Leader 是负责协调各个 Sentinel 节点,执行一些关键操作,像判断节点状态、发起故障转移。

防止脑裂

  1. 节点的心跳监测
  2. 多个 Sentinel 达成共识,认为某个节点真的下线了,才会触发故障转移
  3. 设置quorum 参数,规定多少个 Sentinel 同意才算节点下线

集群

新节点加入集群

节点A想加入,找到集群中的节点B

  1. 节点A按照节点B的IP和端口号,发送MEET
  2. 节点B返回PONG
  3. 节点A发送PING

数据分片

  1. 共有 16384 个槽,数据key通过CRC16算法计算后取模分配到槽.
  2. 每个节点负责部分槽,用16384个bit来表示自己是否负责某个槽, 此信息总共只占用 2KB
  3. 客户端与 Redis 集群建立连接之后,客户端会从集群的任意节点那里获取完整的槽位分配信息。(CLUSTER SLOTS命令获取完整信息。CLUSTER KEYSLOT “user:123"返回槽编号)
  4. 可以融合主从复制,集群中的每个主节点可以拥有从节点

可靠性

  1. 一个槽可能被多个 Redis 节点负责,主要是一个主节点和多个从节点。
  2. 当一个节点接收到写操作,它会把这个操作同步给其他负责相同槽数据的节点,确保数据一致。

删除/新增节点

  1. 新增节点时,一般会从现有节点中划分一部分槽和数据给它,这个过程叫数据迁移
  2. 删除节点,先把它负责的槽和数据迁移到其他节点,确保数据不丢,然后才能移除。

Gossip协议

  1. 节点定期向随机选择的几个节点发送PING消息,包含集群元信息(节点状态、槽分配)
  2. 超时未相应的节点会被标记为PFAIL
  3. 当多数主节点确认某节点为PFAIL时,升级为FAIL状态,触发故障转移,从节点发起选举成为新主节点

脑裂问题

在网络分区(Network Partition)的极端场景下,集群被分割成多个无法互相通信的子集群,每个子集群误认为自己是唯一存活的部分。后果:不同子集群中的主节点可能写入相同哈希槽的数据

如果分区后某个节点无法和多数节点通信,它会停止接受写请求,避免数据不一致。