类似于Raft的共识算法:每个哨兵设置随机超时时间,超时请求其他哨兵为自己投票,其他收到第一个投票确认,最多票成“领导”,没有则重新选举,直到选出
1、有感知异常
如用读写分离:读从不受影响。主库挂,没选出新,写失败,失败时间 = 主从切换 + 客户端感知到新主库时间。
2、无感知异常
写失败请求缓存或写入消息队列,切换完,发给新主,适合:写入请求返回值不敏感业务,还要业务层做适配,切换时间过长,重放请求时间也长
1)主库响应时间,可配置down-after-milliseconds参数。越短越敏感,可能因为网络拥塞发生不必要切换,折中判断
2)缓存写请求写入到新库中,保证后续写不受到影响,具体做法:
(1)哨兵主动通知客户端:哨兵把新主库地址写入自己实例的pubsub(switch-master)中。客户端订阅pubsub,主库变,拿新地址,写新主库
(2)如错过哨兵通知,或者处理失败,主动去获取新主从地址访问。
所以,访问主从库时,不能写死主从库地址,要从哨兵集群中获最新(sentinel get-master-addr-by-name命令),切换、重连,都拿到最新地址
ps:Redis的SDK提供通过哨兵拿到实例地址,直接访问,不需自己实现这些逻辑。1)对于只有主从实例,客户端和哨兵配合使用。2)分片集群模式,这些逻辑都在proxy层,客户端也不需要关心,Codis就这么做
3、哨兵集群中实例挂了,会影响主库状态判断和选主吗?
只要集群中大多数节点状态正常,集群依旧可以对外提供服务
“拜占庭将军”问题,不仅解决了容错问题,还解决错误节点
https://time.geekbang.org/column/article/274483
网友评论