Redis 主从复制
为了分担单机 redis 的数据服务压力,需要进行读写分离,所以搭建 redis 的主从结构,主节点负责写,从节点负责读,主节点定期把数据同步到从节点。
配置主从
# 配置文件中增加一行以哪个 redis 为主
slaveof ip port
# 主节点的密码
masterauth h123
# 从节点只读,默认配置
slave-read-only yes
# 关闭 TCP_NODELAY,无论多大的包都直接发送,默认即可
repl-disable-tcp-nodelay no
# 主节点默认每 10 秒向从节点发送心跳包,默认即可
repl-ping-slave-period 10
主从拓扑结构
slaveof 只是说明本机是哪台的从节点,所以很灵活的实现可种主从结构
- 一主一从:用于主节点故障转移从节点,当主节点的“写”命令并发高且需要持久化,可以只在从节点开启 AOF(主节点不需要),这样即保证了数据的安全性,也避免持久化对主节点的影响
- 一主多从:用于读场景比较多的场合,但这样会造成主节点需要同步较多的从节点,影响主节点的带宽。
- 树状主从:主节点推送更少的从节点,由从节点来递归推送
可以使用 info 命令查询当前 redis 的从节点个数和位置,需要自己依次遍历查询才能得到完整的拓扑结构
数据同步
redis 2.8 版本以上使用 psync
命令完成同步,过程分 全量复制 与部分复制
- 全量复制:一般用于初次复制场景(第一次建立 SLAVE 后全量)
- 部分复制:网络出现问题,从节点再次连接主节点时,主节点补发缺少的数据,每次数据增量同步
故障修复
当主节点出现故障时,已经不能对外提供写服务,但从节点可以提供读服务
可以将其中一台从节点转变成主节点,需要人工处理,无法实现高可用
处理流程
- 修改一台从节点为主节点,在节点执行
slaveof no one
- 让其它从节点以现在的主节点为主节点,redis-cli 执行
slaveof ip port
Redis 哨兵机制(Sentinel)
哨兵机制主要是为了解决主从复制不能自动切换 master 的问题,当主节点故障时,由 sentinel 自动完成故障发现和修复,并通知应用方,实现高可用
配置哨兵节点配置文件,并启动三个哨兵
# 后台启动
daemonize yes
# 监控主节点
sentinel monitor mymaster 127.0.0.1 6379 1
# 启动哨兵
./redis-sentinel conf/sentinel.conf
哨兵的监控任务
- 每 10 秒会向主节点和从节点发送
info
命令获取最新拓扑图 - 每个哨兵节点会每隔 2 秒向 redis 数据节点的指定主题 (__sentinel__:hello) 上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息;同时每个哨兵节点自己也会订阅这个主题,用来了解其它节点的判断,其实就是通过 publish/subscribe 来完成的。
- 每隔 1 秒每个哨兵会向主节点,从节点及其余哨兵节点发送一次 ping 命令做心跳检查,用来判断节点是否正常。
判断主节点是否异常
主观下线(sdown):ping 命令如果在配置的 down-after-milliseconds
之后没有收到有效回复,那么就认为该数据节点主观下线。
客观下线:超过选举个数哨兵认为异常
当有哨兵节点判断主节点异常时,此时该哨兵节点会通过指令 sentinel is-masterdown-by-addr
寻求其它哨兵节点对主节点的判断,当超过 quorum(选举)个数的哨兵节点回答下线,则认为该主节点客观下线
哨兵领导者的选举
当主节点客观下线时,需要选举出一个哨兵节点做为哨兵领导者,以完成后续选出新的主节点的工作。
这个选举的大体思路是:
- 每个哨兵节点通过向其他哨兵节点发送
sentinel is-master-down-by addr
命令来申请成为哨兵领导者。 - 而每个哨兵节点在收到一个
sentinel is-master-down-by addr
命令时,只允许给第一个节点投票,其他节点的该命令都会被拒绝。 - 如果一个哨兵节点收到了半数以上的同意票,则成为哨兵领导者。
- 如果前面三步在一定时间内都没有选出一个哨兵领导者,将重新开始下一次选举。
可以看到,这个选举领导者的流程很像 Raft 中选举 Leader 的流程。
如何选择谁成为主节点
在剩下的从节点中,按照以下顺序来选择新的主节点:
- 过滤掉“不健康”的数据节点:比如主观下线、断线的从节点、五秒内没有回复过哨兵节点 Ping 命令的节点、与主节点失联的从节点。
- 选择 Slave-Priority(从节点优先级)最高的从节点,如果存在则返回,不存在则继续后面的流程。
- 选择复制偏移量最大的从节点,这意味着这个从节点上面的数据最完整,如果存在则返回,不存在则继续后面的流程。
- 到了这里,所有剩余从节点的状态都是一样的,选择 runid 最小的从节点。
提升从节点为主节点
最后就是把从节点转移成主节点,并让其它从节点以它为主节点,和手动处理是一样的流程,只是发起命令人变成了哨兵
- 修改它为主节点,在节点执行
slaveof no one
- 让其它从节点以现在的主节点为主节点,执行
slaveof ip port
- 哨兵节点集合会将原来的主节点更新为从节点,当其恢复之后命令它去复制新的主节点的数据。