一、Sentinel 实现原理
接下来我们就来看下 Sentinel 的实现原理,主要分为以下三个步骤。
①、检测问题,主要讲的是三个定时任务,这三个内部的执行任务可以保证出现问题马上让 Sentinel 知道。
②、发现问题,主要讲的是主观下线和客观下线。当有一台 Sentinel 机器发现问题时,它就会主观对它主观下线,但是当多个 Sentinel 都发现有问题的时候,才会出现客观下线。
③、找到解决问题的人,主要讲的是领导者选举,如何在 Sentinel 内部多台节点做领导者选举,选出一个领导者。
④、解决问题,主要讲的是故障转移,即如何进行故障转移。
三个定时任务:
首先要说的是内部 Sentinel 会执行以下三个定时任务。
每10秒每个 Sentinel 对 Master 和 Slave 执行一次 Info Replication。
每2秒每个 Sentinel 通过 Master 节点的 channel 交换信息(pub/sub)。
每1秒每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping。
第1个定时任务,指的是 Redis Sentinel 可以对 Redis 节点做失败判断和故障转移,在 Redis 内部有三个定时任务作为基础,来 Info Replication 发现 Slave 节点,这个命令可以确定主从关系。
第2个定时任务,类似于发布订阅,Sentinel 会对主从关系进行判定,通过 sentinel:hello 频道交互。了解主从关系可以帮助更好的自动化操作 Redis。然后 Sentinel 会告知系统消息给其它 Sentinel 节点,最终达到共识,同时 Sentinel 节点能够互相感知到对方。
第3个定时任务,指的是对每个节点和其它 Sentinel 进行心跳检测,它是失败判定的依据。
主观下线和客观下线:
回顾一下 Sentinel 的配置。
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
Sentinel 会 ping 每个节点,如果超过30秒,依然没有回复的话,做下线的判断。
那么什么是主观下线呢?
每个 Sentinel 节点对 Redis 节点失败的“偏见”。之所以是偏见,只是因为某一台机器30秒内没有得到回复。
那么如何做到客观下线呢?
这个时候需要所有 Sentinel 节点都发现它30秒内无回复,才会达到共识。
领导者选举方式:
①、每个做主观下线的sentinel节点,会向其他的sentinel节点发送命令,要求将它设置成为领导者
②、收到命令sentinel节点,如果没有同意通过其它节点发送的命令,那么就会同意请求,否则就会拒绝
③、如果sentinel节点发现自己票数超过半数,同时也超过了sentinel monitor mymaster 127.0.0.1 6379 2 超过2个的时候,就会成为领导者
④、进行故障转移操作
如何选择“合适的”Slave 节点:
Redis 内部其实是有一个优先级配置的,在配置文件中 slave-priority,这个参数是 Salve 节点的优先级配置,如果存在则返回,如果不存在则继续。
当上面这个优先级不满足的时候,Redis 还会选择复制偏移量最大的 Slave节点,如果存在则返回,如果不存在则继续。之所以选择偏移量最大,这是因为偏移量越小,和 Master 的数据越不接近,现在 Master挂掉了,说明这个偏移量小的机器数据也可能存在问题,这就是为什么要选偏移量最大的 Slave 的原因。
如果发现偏移量都一样,这个时候 Redis 会默认选择 runid 最小的节点。
二、生产环境中部署技巧
1)Sentinel 节点不应该部署在一台物理“机器”上。
这里特意强调物理机是因为一台物理机做成了若干虚拟机或者现今比较流行的容器,它们虽然有不同的 IP 地址,但实际上它们都是同一台物理机,同一台物理机意味着如果这台机器有什么硬件故障,所有的虚拟机都会受到影响,为了实现 Sentinel 节点集合真正的高可用,请勿将 Sentinel 节点部署在同一台物理机器上。
2)部署至少三个且奇数个的 Sentinel 节点。
3个以上是通过增加 Sentinel 节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加1个节点,奇数个节点可以在满足该条件的基础上节省一个节点。
三、哨兵常见问题
哨兵集群在发现 master 节点挂掉后会进行故障转移,也就是启动其中一个slave 节点为master 节点。在这过程中,可能会导致数据丢失的情况。
1、异步复制导致数据丢失
因为master->slave的复制是异步,所以可能有部分还没来得及复制到slave就宕机了,此时这些部分数据就丢失了。
在异步复制的过程当中,通过min-slaves-max-lag这个配置,就可以确保的说,一旦slave复制数据和ack延迟时间太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样就可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低到可控范围内。
2、集群脑裂导致数据丢失
脑裂:也就是说,某个master所在机器突然脱离了正常的网络,跟其它slave机器不能连接,但是实际上master还运行着。**
造成的问题:
此时哨兵可能就会认为master宕机了,然后开始选举,将其它slave切换成master。这时候集群里就会有2个master,也就是所谓的脑裂。**
此时虽然某个slave被切换成了master,但是可能client还没来得及切换成新的master,还继续写向旧的master的数据可能就丢失了。
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会被清空,重新从新的master复制数据。
如何怎么解决?
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
集群脑裂因为client还没来得及切换成新的master,还继续写向旧的master的数据可能就丢失了通过min-slaves-to-write 确保必须是有多少个从节点连接,并且延迟时间小于min-slaves-max-lag多少秒。
当然对于客户端需要怎么做呢?
对于client来讲,就需要做些处理,比如先将数据缓存到内存当中,然后过一段时间处理,或者连接失败,接收到错误切换新的master处理。