序言
上篇文章我们说到过,Redis 使用了主从复制的机制来保证了相对的高可用,以及使用读写分离缓解了主机的压力。但是,如果我们的主机如果因为各种因素掉线了,此时从机不会主动的去上位当老大,必须我们手动的去提升从机。
如果我们长时间没有及时的去调整,那我们的系统就会一直处于 只可读 的状态,这显然不是合理的。为了更加智能的管理,我们需要额外的机制来监督主机并发生故障的时候及时地替换主机。
一、哨兵集群的架构
哨兵在部署时一般会部署多台并且会采用奇数个,是因为:
- 不仅避免了单台下线导致监控失效,还避免了因为网络因素误判主机下线
- 采用奇数个哨兵是因为后续会有投票的过程,尽量避免出现平局的情况
整体的结构如下:
每隔一定的时间哨兵会向主从设备发送心跳包探测对方的状态。
二、哨兵结点的配置
如果你的系统里面找不到默认的 sentinel.conf
文件,没关系,我们自己配置一个,整体的选项内容没多少个,下面一一介绍:
# 监控主节点(格式:sentinel monitor <主节点名> <IP> <端口> <法定票数>)
# 法定票数(quorum)就是进行故障判定,一般设置为 哨兵数量 / 2 + 1
sentinel monitor mymaster 192.168.1.100 6379 2
# 主节点密码(若设置)
sentinel auth-pass mymaster your_master_password
# 故障判定时间(毫秒,默认 30 秒)
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 180000
配置好文件之后我们以这样的方式启动服务器端:
redis-server /path/to/sentinel.conf --sentinel
之后我们可以查看日志或者是其他方式来查看是否启动成功,在这里因为笔者手上硬件设备的限制不能很好的演示。
三、哨兵机制的工作原理
首先哨兵结点不负责任何的业务逻辑处理,而专注于四件事:
- 监控:sentinel 不断检查主从设备是否按照预期工作
- 通知:可以通知其他的 sentinel 其中一个受监控的 Redis 实例有问题
- 自动故障转移:明确主机出现问题后,会选出一个 sentinel 来执行故障转移,将一个从机提升为主机并让其他的从机重新认主
- 配置提供:将新的主机的地址通知到客户端
那么我们围绕着一个完整的过程来尝试理解吧:
1. 监控主从
Redis 哨兵的核心功能之一是监控主节点和从节点的健康状态。哨兵会定期向主节点和从节点发送 PING 请求,并等待响应,以确定节点是否健康。
2. 主观下线
当我们的请求发出在指定时间(down-after-milliseconds
)内没有得到回复时,该哨兵会认为主机故障了,这就是主观下线。但是我们需要知道,网络是不可靠的有可能我们的这个信息因为各种因素没有收到,所以不能直接判定该主机确实是故障了,这也是为什么需要多个哨兵的原因。
3. 客观下线
当某个哨兵结点认为主机故障时,会发起一个投票来查看其他哨兵的情况。如果票数的值满足了 quorum,那么我们就客观的认为这个主机确实是故障了。相反,如果票数不满足的话,就不会进一步操作。
4. 兵王之争
现在就需要触发故障转移了,问题来了,哪一个哨兵结点来进行这个操作呢?是发现那个人吗?但是万一两个哨兵同时发现呢?那我们就投投出一个人来吧!
投票的过程大致是如下的,发现主机故障的哨兵会自动变为候选人,候选人会投自己一票,然后向其他的哨兵发起投票请求,当他的票数累积到 quorum 时,他就会通告其他哨兵自己正式成为了 leader。
如果过程是这样的话就好了,但是万一有多个候选人呢?多个候选人会向其他的哨兵发起投票请求,但是每一个人只有一张票。最终如果出现了平局的情况(所以我们一般设置奇数个数量的哨兵避免这个尴尬的情况),那只有再来一次了。
5. 选出新的主机
这个过程可有讲究了,首先我们选出的机器需要稳定,如果网络状态都不稳定了那又会发生转移的操作,其次我还需要他的数据要是最新的,每一个结点可能同步主机的进度不一样,但是肯定需要数据最新的。围绕这个目的,咋们看看具体过程吧。
首先需要选出候选人,候选人的网络是需要稳定的,怎么判断的呢,如下:
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
如果发现与主服务器断开连接的时间超过配置的主服务器超时时间(down-after-milliseconds
选项)的十倍,再加上从 Sentinel
执行故障转移的角度来看主服务器不可用的时间,则认为该副本不适合进行故障转移,并将被跳过。
优先级。每一个设备都有一个优先级别的设置,数值越低优先级别越高,怎么评判一个设备的优先级别呢?由多个角度这个设备的硬件实力,网络实力等。
同步进度。如果优先级别相同,我们再来考虑这个设备的同步进度,进度越高代表数据越接近实时的,那我们优先选择该设备。
运行ID。如果还是不能选出来的话,那直接选择 ID 较小的作为我们的新的主机。
现在我们已经确定新的主机 ID 了,怎么让该从机变为主机呢?该哨兵结点只需要向主节点发送 slaveof no one
就好啦。
6. 认主(从机指向新的主机)
现在新的主机已经诞生了,现在需要我们进行下一步了,那就是让其他的主机重新指向新的主机,方法也很简单,向其他的从节点发送 slaveof <ip> <port>
即可绑定新的主机。
7. 通知客户端主机的修改
Redis 提供了一个发布/订阅(Pub/Sub) 功能,客户端可以订阅特定的频道,当有消息发布到这些频道时,客户端会收到通知。如果主机有变更,比如数据修改或主从切换,可以通过 Redis 发布相应的消息,通知订阅的客户端进行处理。
8. 旧主变从
原来的主机哨兵结点会持续地监视他,当我们他上线时会发送 slaveof <ip> <port>
来让他绑定新的主机,所以不要认为他一回来就会霸占主机的位置。
总结
这就是大致我们地哨兵结点工作的方式,在主机发生故障的时刻能快速的切换一个从机上位为主机,保障服务稳定的进行。