原理
主从复用是高并发的基石,哨兵模式提供了主从架构中宕机后自动恢复能力,Gossip协议和一致性哈希协议提供了集群中新增或退出节点是数据自动重分配问题。
主从复制
一主多从,从节点可再有从节点,从节点拷贝主节点数据。用户操作时实现读写分离,从节点提供读功能,主节点提供写功能。
主从复制包括全量复制、长连接的命令发送、增量复制。
全量复制:
主节点 fork()
一个子进程调用 rdbSave()
函数生成 rdb 快照文件,生成完毕后调用 updateSlavesWaitingBgsave()
将 rdb 文件发送给从节点,从节点收到后解析重新导入数据。
长连接命令复制:
第一次全量复制后,主从节点间维持长连接。所谓命令传播当Master节点每处理完一个命令都会把命令广播给所有的子节点,而每个子节点接收到Master的广播过来的命令后,会在处理完之后继续广播给自己的子节点。需要注意的是,Redis的命令广播是异步的操作。即Master节点处理完客户端的命令之后会立马向客户端返回结果,而不会一直等待所有的子节点都确认完成操作后再返回以保证Redis高效的性能。
增量复制:
从节点断连后恢复时如何同步数据,通过开辟一个缓冲区(默认1MB),每次处理完命令后将数据先写入 repl_backlog
缓冲区中,再发送给子节点,它是一个环形缓冲区,数据量有限。子节点断联后主节点会选择性发送该缓冲区数据,但是如果数据已经被覆盖就只能进行全量复制。
哨兵模式
哨兵功能如下:
监控 Master、Slave、其它 Sentinel 节点是否正常工作;
master 故障时,选择一个 Slave 升级为 Master 代替工作,并通知客户端新 Master地址;
集群节点故障时,执行特定脚本或者订阅告知系统管理员;
Sentinel 通常以集群形式存在,防止因为网络原因误判而导致 sentinel
、master
节点间无法通信。
启动 Sentinel 及配置
redis-server /path/to/sentinel.conf --sentinel
配置文件信息:
# 哨兵监控哪个 Master,以及认定故障所需要的法团数
sentinel monitor mymaster 127.0.0.1 6379 2
# 哨兵认为服务器已经断线的临界阈值
sentinel down-after-milliseconds mymaster 60000
# 哨兵发现故障时的重试时间间隔
sentinel failover-timeout mymaster 180000
# 同步新 Master 时同时发起复制的 slave 节点个数
sentinel parallel-syncs mymaster 1
上述配置,Sentinel 只是知道了主节点的地址信息,那么是如何监控其它 Sentinel、Slave ?
Sentinel 连接到 Master 后发送 INFO
命令,命令中包含了其它 slave 节点信息;
Sentinel 通过发布订阅 __sentinel__:hello
通道来实现获取其它 Sentinel 节点信息的功能,每隔 2s 发布自己的状态(IP、port、status);
主观下线和客观下线
如果某个 Sentinel
判定 master 节点故障,就会投出一票 S_DOWN
,当足够多的 sentinel
节点判定 master 节点故障(总票数大于 quarom)就认为真正的下线了。
S_DOWN 状态:
Sentinel 节点会定时向被监控节点发送 PING/INFO
命令监控状态,当出现以下情况认为该节点主观下线:
超过了配置的 down-after-milliseconds
还没有收到回复,就认为主观下线;
原监控节点为Master,但是收到的回复显示为 Slave,说明发生了 failover,认为下线。
一个 Sentinel 节点认为监控节点处于主观下线状态,就回去询问其它 Sentinel 节点进行投票判断是否客观下线。
O_DOWN 状态:
各个sentinel节点之间定时会互相通信来同步各自对于Master节点的状态判断,,所以如果sentinel_A节点判定Master节点为S_DOWN,一段时间之后其他所有的sentinel节点就都会知道sentinel_A节点对Master的判定。O_DOWN的状态判定算法很简单,当sentinel_A判定Master处于S_DOWN之后,会紧接着查看其他sentinel节点对master节点的判断。由于sentinel节点之间会定期互相同步信息,所以sentinel_A节点只需要检查自己之前保存的其他节点的判断结果即可。如果发现超过qurom个sentinel节点都判断master节点为S_DOWN,那么sentinel节点就会判定该节点处于O_DOWN状态。
故障恢复
先概述故障恢复的步骤:
设置新的Master节点替换掉原来的故障Master节点。
设置其他的节点成为新的Master节点的Slave节点用于主从复制。
告知客户端新的master节点地址信息,同时执行必要的脚本来通知系统管理员。
现在有多个 Sentinel 节点,故障恢复过程需要一个哨兵节点来领导,所以需要先选举出一个 Master Sentinel
节点。
Sentinel 选举新的 Master 节点使用了 Raft 一致性算法,先随机让所有节点过期一个时间,然后发起拉票,当某个节点获取的票数超过了 max{(|sentinel|/2 + 1)}, qurom
时选举出新 Leader 节点。
接着由 Sentinel Master
节点来主持更新 Slave 节点操作,根据以下流程执行:
根据指定优先级选择:slave 启动时可以手动设置节点优先级,那么选新 Leader 时可以优先选该节点。
根据数据更新程度选:所有 slave 节点复制时会记录 offset,根据 slave_repl_offset
选举出数据最新的节点。
根据 runId
选择:每个节点启动时都有一个 runId,选最小的。
新 leader 选举出后,Sentinel Master
向该节点发送 slaveof no one
命令来提升该节点为 master 节点。当 Leader 节点从该 slave 节点的 INFO 命令回复中确认该节点已经成为 Master 节点后,就会向其它 Redis 子节点发送 slaveof
命令,使他们成为新 Master的子节点。
实操
集群搭建
基于 Docker 搭建 Redis 集群:https://www.cnblogs.com/niceyoo/p/14118146.html