Redis如何做到高可用


哨兵模式

Sentinel 是 Redis 的一种运行模式 ,它主要的作用就是对 Redis 运行节点进行监控。当 master 节点出现故障的时候, Sentinel 会帮助我们实现故障转移,确保整个 Redis 系统的可用性。整个过程完全自动,不需要人工介入。

  1. 集群监控:复制监控master与slave进程是否正常工作
  2. 消息通知:如果某个实例有古樟,那么哨兵负责发送消息作为报警通知给管理员
  3. 故障转移:master挂掉,会自动转移到slave
  4. 配置中心:如果故障转移发生,会通知客户端新的master地址
  • 故障转移时,判断一个master是否宕机,需要大部分哨兵同意才行,涉及到分布式选举
  • 及时部分哨兵节点故障,哨兵集群还能正常工作

哨兵核心知识

  • 哨兵需要至少3个实例保证自己的健壮
  • 哨兵+Redis主从的部署架构,不保证数据不丢失,只能保证Redis集群的高可用

哨兵主备切换的数据丢失问题

导致数据丢失的两种情况

主备切换的过程,可能会导致数据丢失

  • 异步复制导致数据丢失 因为master到slave复制是异步的,所以可能有部分数据没有复制到slave,master就宕机了,此时部分数据就丢失。

  • 脑裂导致数据丢失 就是在主从集群中,同时有两个主节点,它们都能够接收写请求。而脑裂最直接的影响就是客户端不知道应该往那个主节点写入数据,结果就是不同的客户端往不同的主节点写入数据,严重的话,脑裂会导致数据丢失。

数据丢失的解决方案

进行如下配置

min-slaves-to-write 1
min-slaves-max-lag 10

表示,要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒。

如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了。

  • 减少异步复制数据丢失 有了min-slaves-max-lag这个配置,可以确保一旦slave复制数据延时太长,就认为可能master宕机后损失数据太多,就拒绝写请求,可以把master宕机时由于部分数据没同步到slave导致数据的丢失降低在可控范围。

  • 减少脑裂的数据丢失 如果一个master出现了脑裂,其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量slave发送数据,而且slave超过10s没有给自己消息,那么就直接拒绝客户端写请求。因此最多丢失10s的数据

sdown和odown转换机制

  • sdown是主观宕机,就一个哨兵如果觉得一个master宕机,就是主观宕机 sdown达成的条件很简单,如果一个哨兵ping一个master超过指定毫秒,就主观认为master宕机了

  • odown是客观宕机,如果半数以上的哨兵觉得一个master宕机,就是客观宕机 如果一个哨兵在指定时间内,收到了半数以上的其他哨兵也认为那个master宕机,那就是客观宕机

哨兵集群自动发现机制

哨兵之间的发现,是通过Redis的pub/sub系统实现的,每个哨兵都会往一个channel发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知其他哨兵的存在。

每隔2s,每个哨兵都会往自己监控的某个channel发送一个消息,内容是自己的host、ip和runid与对这个master的监控配置。

每个哨兵也会去监听自己的监控的每个master+slave对应的channel,然后去感知同样在监控这个channel其他哨兵的存在。

每个哨兵还会与其他哨兵交换对master的监控配置,互相进行监控配置同步。

slave配置的自动纠正

哨兵会负责启动纠正slave的一些配置,比如slave如果要成潜在的master候选人,哨兵会确保slave复制现有master的数据;如果slave连接一个错误的master上,比如故障转移之后,那么哨兵会确保他们连接到正确的master上。

slave->master选举算法

如果一个master被认为客观宕机,而且majority数量的哨兵都会允许主备切换,那么某个哨兵就会执行主备切换操作,此时先选举一个slave,会考虑slave一些信息:

  • 跟master断开连接的时长
  • slave优先级
  • 复制offset
  • run id 如果一个slave与master断开连接的时间超过了指定时间的10倍+master宕机事件,那么slave会被认为不适合选举为master
    (down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
    

    接下来会对slave进行排序

  • 按照slave优先级排序,slave priority越低,优先级越高
  • 如果slave priority相同,那么看replica offset,哪个复制的数据越多,offset越后,优先级越高。
  • 如果上面两个条件相同,那么选择run id比较小的那个slave

quorum和majority

每次一个哨兵要做主备切换,需要quorum数量的哨兵认为客观下线,然后选举一个哨兵来做切换,这个哨兵还要得到majority哨兵授权,才能正式执行切换。

如果quorum<majority,比如5个哨兵,majority就是3,quorum设置为2,那么3个哨兵授权就可以执行切换。

但是如果 quorum >= majority,那么必须 quorum 数量的哨兵都授权,比如 5 个哨兵,quorum 是 5,那么必须 5 个哨兵都同意授权,才能执行切换。

configuration epoch

哨兵会对一套 Redis master+slaves 进行监控,有相应的监控的配置。

执行切换的那个哨兵,会从要切换到的新 master(salve->master)那里得到一个 configuration epoch,这就是一个 version 号,每次切换的 version 号都必须是唯一的。

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待 failover-timeout 时间,然后接替继续执行切换,此时会重新获取一个新的 configuration epoch,作为新的 version 号。

configuration 传播

哨兵完成切换之后,会在自己本地更新生成最新的 master 配置,然后同步给其他的哨兵,就是通过之前说的 pub/sub 消息机制。

这里之前的 version 号就很重要了,因为各种消息都是通过一个 channel 去发布和监听的,所以一个哨兵完成一次新的切换之后,新的 master 配置是跟着新的 version 号的。其他的哨兵都是根据版本号的大小来更新自己的 master 配置的。




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 2379. Minimum Recolors to Get K Consecutive Black Blocks
  • 2471. Minimum Number of Operations to Sort a Binary Tree by Level
  • 1387. Sort Integers by The Power Value
  • 2090. K Radius Subarray Averages
  • 2545. Sort the Students by Their Kth Score