redis哨兵是怎么工作的
哨兵作用
- 监控整个主数据库和从数据库,观察它们是否正常运行
- 当主数据库发生异常时,自动将从数据库升级为主数据库,继续保证整个服务的文档
哨兵是怎样工作的
- 每隔sentinel以每秒钟一次的频率向他所知的主节点,从节点以及其他sentinel实例发送一个ping命令
- 如果一个实例(instance)距离最后一次有效恢复PING命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被当前的sentinel标记为主观下线
- 如果一个主节点被标记为主观下线,则正在监视这个主节点的所有sentinel要以每秒一次的频率确认主节点确定既然进入了主观下线状态
- 当有足够数量的sentinel(大于等于配置文件指定的值)在指定的时间范围内确认主节点的确进入了主观下线状态,则这个主节点会被标记为客观下线。
- 当主节点被sentinel标记为客观下线时,sentinel向下线的主节点的所有从节点发送INFO命令的频率会从10s一次改为每秒一次(在一般情况下,每个sentinel会议每10 秒一次的频率向它已知的所有主节点,从节点发送 INFO 命令 )
- 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会变成主观下线。若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
- sentinel节点会与其他sentinel节点进行“沟通”,投票选举一个sentinel节点进行故障处理,在从节点中选取一个主节点,其他从节点挂载到新的主节点自动复制新主节点的数据
哨兵的选举过程
- 第一个发现该master挂了的哨兵,会向每个哨兵发送命令,让对方选举自己成为领头哨兵
- 其他哨兵如何没有选举过他人,就会将这一票投给第一个发现该master挂了的哨兵
- 第一个发现该master挂了的哨兵如果发送有超过一般的哨兵投给自己,并且其数量也超过了设定的quoram参数,那么该哨兵就成了领头哨兵
- 如果多个哨兵同时参与这个选举,那么就会重复该过程,知道选出一个领头哨兵
选出领头哨兵后,就开始了故障修复,会从选出一个从数据库作为新的master
故障转移时会从剩下的slave选举一个新的master,被选举为master的标准是什么?
如果一个master被认为宕机了,而且领头哨兵允许了主从切换,那么某个哨兵就会执行主从切换操作,此时时首先要选举一个slave来,会考虑slave的一些信息
- 跟master断开连接的时长。
如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master.
- slave优先级
按照slave优先级进行排序,slave priority越低,优先级就越高
- 复制offset。
如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
- run id
如果上面两个条件都相同,那么选择一个run id比较小的那个slave
执行切换的那个哨兵在完成故障转移后会做什么
会进行configuration配置信息传播
哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后通过pub/sub消息机制同步给其他的哨兵。
同步配置的时候其他哨兵根据什么更新自己的配置呢?
执行切换的那个哨兵,会从要切换的新主节点(slave->master)哪里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的
如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch 作为新的version号。
这个version就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的,其他的哨兵都是根据版本号的大小来更新自己的master配置的
哨兵模式主从切换数据丢失问题
会产生数据丢失的场景
异步复制导致的数据丢失
因为主节点–> 从节点的复制是异步的,所以可能有部分数据还没有复制到从节点,主节点就宕机了,此时主节点中的数据和从节点中的数据不同步,即数据丢失。
脑裂导致数据丢失
什么是脑裂
当某个主节点所在的机器突然脱离正常的网络,不能与其他的从节点连接,但实际上主节点还在运行着,这时候哨兵就会认为主节点宕机了,然后开启选举,将其他的从节点推举为新节点,这时候集群中就会出现两个主机,这种现象就是脑裂
脑裂引发的数据丢失问题
当一个从节点被推举为新的主节点时,但此时的客户端还没来得及切换到新的主节点,客户端仍然继续向旧的主节点中传输数据,因此当旧的主节点恢复的时候,会成为一个新的主节点,并挂在新的主节点上,自己的数据就会清空,重新从新的主节点复制数据
解决方案
redis层面:通过配置控制同步事件
redis.conf配置如下:
min-slaves-to-write 1
min-slaves-max-lag 10
配置说明:
- 该配置必须至少有1个从节点,数据复制和同步延迟不能超过10s
- 如果说一旦所有的从节点,数据复制和同步的延迟超过了10s,那么主节点就会拒绝接收任何请求
作用:
-
减少异步复制的数据丢失
- 配置min-slaves-max-lag为10s之后,根据目前主节点–>从节点的复制速度,如果数据同步完成所需要时间超过10s,就会认为主节点未来宕机后损失的数据会很多,主节点就拒绝写入新请求
- 这样就能将主节点和从节点的数据差控制在10s之内,即使主节点宕机也只是这未复制的10s数据
-
减少脑裂的数据丢失:
- 如果不能继续给指定数量的从节点发送数据,而且从节点超过10s没有给自己ack消息,那么就直接拒绝写入新请求,这样脑裂后的旧主节点就不会接收客户端的新数据,也就避免了数据丢失
- 因此在脑裂场景下,最多就丢失10秒的数据
生产者方面:降级限流
- 降级:先将消息写到本地磁盘中或者放到临时的消息队列中,每隔10分钟去本地磁盘或者队列中取,来尝试重新发给主节点
- 限流:在网关减慢请求涌入的速度