02-Redis 部署模式02哨兵(重要)

官网保平安:https://redis.io/

Sentinel(哨兵)(>=2.8版本)

Redis Sentinel 实现 Redis 集群高可用,只是在主从复制实现集群的基础下,多了一个 Sentinel 角色来帮助我们监控 Redis 节点的运行状态并自动实现故障转移。

当 master 出现故障的时候,Sentinel 会帮助我们实现故障转移,自动根据一定的规则选出一个 slave 升级为 master,确保整个 Redis 系统的可用性。整个过程完全自动,不需要人工介入。

Sentinel 有什么作用

相关问题:

  • 为什么建议部署多个 Sentinel 节点(哨兵集群)?

根据 Redis Sentinel 官方文档 的介绍,Sentinel 节点主要可以提供 4 个功能:

  • 监控: 监控所有 redis 节点(包括 Sentinel 节点自身)的状态是否正常。
  • 故障转移: 如果一个 master 出现故障,Sentinel 会帮助我们实现故障转移,自动将某一台 slave 升级为 master,确保整个 Redis 系统的可用性。
  • 通知: 通知 slave 新的 master 连接信息,让它们执行 replicaof 成为新的 master 的 slave。
  • 配置提供: 客户端连接 Sentinel 请求 master 的地址,如果发生故障转移,Sentinel 会通知新的 master 链接信息给客户端。

Redis Sentinel 本身设计的就是一个分布式系统,建议多个 Sentinel 节点协作运行。这样做的好处是:

  • 多个 Sentinel 节点通过投票的方式来确定 Sentinel 节点是否真的不可用,避免误判(比如网络问题可能会导致误判)。
  • Sentinel 自身就是高可用。

如果想要实现高可用,建议将哨兵 Sentinel 配置成单数且大于等于 3 台。

一个最简易的 Redis Sentinel 集群如下所示(官方文档中的一个例子),其中:

  • M1 表示 master,R2、R3 表示 slave;
  • S1、S2、S3 都是 Sentinel;
  • quorum 表示判定 master 失效最少需要的仲裁节点数。这里的值为 2,也就是说当有 2 个 Sentinel 认为 master 失效时,master 才算真正失效。
1
2
3
4
5
6
7
8
9
10
11
       +----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+

Configuration: quorum = 2

如果 M1 出现问题,只要 S1、S2、S3 其中的两个投票赞同的话,就会开始故障转移工作,从 R2 或者 R3 中重新选出一个作为 master。

为什么 Redis 哨兵集群只有 2 个节点无法正常工作?

在故障转移的时候,需要 majority,也就是大多数哨兵都是运行的,2 个哨兵的 majority 就是 2(2 的 majority=2,3 的 majority=2,5 的 majority=3,4 的 majority=2),2 个哨兵都运行着,就可以允许执行故障转移。

如果此时有一个 Sentinel 挂掉了,此时就没有足够的 majority 来允许执行故障转移,所以故障转移不会执行。

Sentinel 缺点

  • 主从模式,切换需要时间,可能会丢数据。
  • 没有解决 master 写的压力。

Sentinel 原理

相关的问题:

  • 主观下线与客观下线的区别?
  • Sentinel 如何检测节点是否下线?
  • Sentinel 是如何实现故障转移的?
  • Sentinel 如何选择出新的 master?
  • 如何从 Sentinel 集群中选择出 Leader?
  1. 三个定时监控任务:

    1. 每隔10s,每个 Sentinel 节点 会向 master 和 slave 发送 info 命令获取最新的拓扑结构。
    2. 每隔 2s,每个 Sentinel 节点 会向某频道上发送该 Sentinel 节点 对于 master 的判断以及当前 Sl节点 的信息,同时每个 Sentinel 节点 也会订阅该频道,来了解其他 Sentinel 节点 以及它们对 master 的判断(做客观下线依据)。
    3. 每隔 1s,每个 Sentinel 节点 会向 master、slave、其余 Sentinel 节点 发送一条 ping 命令做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达。
  2. 主客观下线:

    1. 主观下线(sdown):

      • 根据第三个定时任务,如果对应的节点超过规定的时间(down-after-millisenconds)没有进行有效回复的话,就会认定为主观下线。但还不是很确定,需要其他 Sentinel 节点的投票。
      • 这里的有效回复不一定是 PONG,可以是-LOADING 或者 -MASTERDOWN
    2. 客观下线(odown):

      • 若主观下线的是 master,会咨询其他 S节点 对该 master 的判断,超过半数,对该 master 做客观下线。
      • 若主观下线的是 slave,不会做什么事情。
    3. 如果没有足够数量的 Sentinel 节点认定 master 已经下线的话,当 master 能对 Sentinel 节点的 PING 命令进行有效回复之后,master 也就不再被认定为主观下线,回归正常。

  3. 选举出某一 Sentinel 节点 作为 Leader,来进行故障转移。

    • 这就需要用到分布式领域的 共识算法 了。简单来说,共识算法就是让分布式系统中的节点就一个问题达成共识。在 Sentinel 选举 leader 这个场景下,这些 Sentinel 要达成的共识就是谁才是 leader 。

    • 大部分共识算法都是基于 Paxos 算法改进而来。Sentinel 选举 leader 用的是 Raft 算法。每个Sentinel 节点 有一票同意权,哪个 Sentinel 节点 做出主观下线的时候,就会询问其他 Sentinel 节点 是否同意其为领导者。获得半数选票的则成为领导者。基本谁先做出客观下线,谁成为领导者。

    想要深入了解 Raft 算法实践以及 Sentinel 选举 leader 的详细过程的同学,推荐阅读下面这两篇文章:

  4. 故障转移(选举新 master 流程):

    选举 master,会考虑 slave 的如下信息:

    1. 跟 master 断开连接的时长。如果一个 slave 跟 master 断开连接已经超过了 down-after-milliseconds 的 10 倍,外加 master 宕机的时长,那么该 slave 就被认为不适合选举为 master。

      • ( down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
    2. slave 优先级。按照 slave 优先级进行排序,优先级最高的直接成为新的 master。如果没有优先级最高的,再判断复制进度。

      • 可以通过 slave-priority 手动设置 slave 的优先级,
    3. 复制进度。Sentinel 总是希望选择出数据最完整(与旧 master 数据最接近)也就是复制进度最快的 slave 被提升为新的 master,复制进度越快得分也就越高。

    4. run id(运行 id)。如果上面两个条件都相同,那么选择一个 run id 比较小的 slave。

      • 每个 redis 节点启动时都有一个 40 字节随机字符串作为运行 id
  5. 如果 master 修复好了,再次启动时候,会变成 slave。

Sentinel 设置

  1. 启动主 Redis:redis-server /etc/redis-6379.conf

  2. 启动从 Redis:redis-server /etc/redis-6380.conf

  3. 找到 /etc/redis-sentinel-8001.conf 配置文件,修改:

    • port = 8001:哨兵的端口。
    • sentinel monitor mymaster 127.0.0.1 6379 2
      • mymaster 是哨兵所在分组的名称。
      • 后面的 IP+端口 是 master 的IP和端口。
      • 最后的 2,意思是 master 被认为的宕机,需要选举新的 master 时,至少要争取到 2 票的赞同,否则故障不会自动转移。
  4. 找到 /etc/redis-sentinel-8002.conf 配置文件,修改:

    • port = 8002:哨兵的端口。
    • sentinel monitor mymaster 127.0.0.1 6379 2
  5. 启动两个哨兵:

    1. 方式一:redis-server --sentinel 命令启动哨兵,示例:redis-server /path/to/sentinel.conf --sentinel
    2. 方式二:redis-sentinel 命令启动哨兵,示例:redis-sentinel /path/to/sentinel.conf

    两个命令都可以启动哨兵服务。

一个常见的最小配置如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 指定要监视的 master
// 127.0.0.1 6379 master 地址
// 2 表示当有 2 sentinel 认为 master 失效时,master 才算真正失效
sentinel monitor mymaster 127.0.0.1 6379 2
// master 节点宕机多长时间才会被 sentinel 认为是失效
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
// 在发生主备切换时最多可以有 5 slave 同时对新的 master 进行同步
sentinel parallel-syncs resque 5

Redis 主从架构数据会丢失吗,为什么?

  • Sentinel 可以防止脑裂吗?

有两种数据丢失的情况:

  1. 异步复制导致的数据丢失:因为 master -> slave 的复制是异步的,所以可能有部分数据还没复制到 slave,master 就宕机了,此时这些部分数据就丢失了。

  2. 脑裂导致的数据丢失:

    1. 某个 master 所在机器突然脱离了正常的网络,跟其他 slave 机器不能连接,但是实际上 master 还运行着,此时哨兵可能就会认为 master 宕机了,然后开启选举,将其他 slave 切换成了 master。
    2. 这个时候,集群里就会有两个 master,也就是所谓的脑裂。此时虽然某个 slave 被切换成了 master,但是可能 client 还没来得及切换到新的 master,还继续写向旧 master 的数据可能也丢失了。
    3. 因此旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master 上去,自己的数据会清空,重新从新的 master 复制数据。

如何解决主从架构数据丢失的问题?

数据丢失的问题是不可避免的,但是我们可以尽量减少。

在 Redis 的配置文件里设置参数

1
2
min-slaves-to-write 1   # 默认 0(表示关闭该功能),用于配置写 master 至少写入的 slave 数量,否则就停止接受新的写入命令请求
min-slaves-max-lag 10 # 默认 10,用于配置 master 多长时间(秒)无法得到 slave 的响应,就认为这个节点失联

上面的配置的意思是:要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒。如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了。

减小 min-slaves-max-lag 参数的值,这样就可以避免在发生故障时大量的数据丢失。

那么对于 client,我们可以采取降级措施,将数据暂时写入本地缓存和磁盘中,在一段时间后重新写入 master 来保证数据不丢失;也可以将数据写入 Kafka 消息队列,隔一段时间去消费 Kafka 中的数据。


02-Redis 部署模式02哨兵(重要)
https://flepeng.github.io/interview-41-数据库-41-Redis-02-Redis-部署模式02哨兵(重要)/
作者
Lepeng
发布于
2020年8月8日
许可协议