高可用
主从复制
主要优点:数据备份、读写分离,通常和哨兵模式结合使用。
主服务器负责读写请求,从服务器默认只负责读请求。
主节点在执行完写请求之后,将写命令同步到从节点,然后从节点再执行这条命令,保证和主节点的数据一致。
- 从节点向主节点发送 SYNC 命令,希望建立连接。
- 主节点回复 FULLRESYNC 命令给从节点,并且携带两个参数:主节点的runID和复制进度offset
- 主节点执行bgsave, 生成RDB文件,传输给从节点。(主节点生成RDB文件期间、传输RDB文件期间,还有从节点加载RDB文件期间,主节点会把新的写命令写入replication buffer中。)
- 从节点将RDB数据加载进内存;主节点把replication buffer中的命令发给从节点,让它执行。
主从节点在完成第一次同步后,就会维护一个TCP长连接。
配置
|
|
问题
如果向主节点请求全量复制的从节点太多,主节点就要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模式,发布给客户端。
继续监控旧主节点。当它重新上线时,把它设置为新主节点的从节点。
选新主节点的过程:
- 排除断开连接次数太多的从节点,它们网络状态不好
- 按从节点的优先级选,slave-priority越低越好
- 若优先级一样,谁的 offset 最大就选谁
- 若 offset 也一样,选 ID 最小的从节点
哨兵leader
Sentinel 集群里的 Leader 是负责协调各个 Sentinel 节点,执行一些关键操作,像判断节点状态、发起故障转移。
防止脑裂
- 节点的心跳监测
- 多个 Sentinel 达成共识,认为某个节点真的下线了,才会触发故障转移
- 设置quorum 参数,规定多少个 Sentinel 同意才算节点下线
集群
新节点加入集群
节点A想加入,找到集群中的节点B
- 节点A按照节点B的IP和端口号,发送MEET
- 节点B返回PONG
- 节点A发送PING
数据分片
- 共有 16384 个槽,数据key通过CRC16算法计算后取模分配到槽.
- 每个节点负责部分槽,用16384个bit来表示自己是否负责某个槽, 此信息总共只占用 2KB
- 客户端与 Redis 集群建立连接之后,客户端会从集群的任意节点那里获取完整的槽位分配信息。(CLUSTER SLOTS命令获取完整信息。CLUSTER KEYSLOT “user:123"返回槽编号)
- 可以融合主从复制,集群中的每个主节点可以拥有从节点
可靠性
- 一个槽可能被多个 Redis 节点负责,主要是一个主节点和多个从节点。
- 当一个节点接收到写操作,它会把这个操作同步给其他负责相同槽数据的节点,确保数据一致。
删除/新增节点
- 新增节点时,一般会从现有节点中划分一部分槽和数据给它,这个过程叫数据迁移。
- 删除节点,先把它负责的槽和数据迁移到其他节点,确保数据不丢,然后才能移除。
Gossip协议
- 节点定期向随机选择的几个节点发送PING消息,包含集群元信息(节点状态、槽分配)
- 超时未相应的节点会被标记为PFAIL
- 当多数主节点确认某节点为PFAIL时,升级为FAIL状态,触发故障转移,从节点发起选举成为新主节点
脑裂问题
在网络分区(Network Partition)的极端场景下,集群被分割成多个无法互相通信的子集群,每个子集群误认为自己是唯一存活的部分。后果:不同子集群中的主节点可能写入相同哈希槽的数据
如果分区后某个节点无法和多数节点通信,它会停止接受写请求,避免数据不一致。