Jamzy Wang

life is a struggle,be willing to do,be happy to bear~~~

Redis Sentinel详解

2015-01-23 23:55

原创声明:本作品采用知识共享署名-非商业性使用 3.0 版本许可协议进行许可,欢迎转载,演绎,但是必须保留本文的署名(包含链接),且不得用于商业目的。

redis 的 sentinel 工具用于管理多个 redis 服务器(如一个master多个slave的服务器群), 该工具执行以下三个任务:

1) 监控(Monitoring)

Sentinel 会不断地检查你的master和从salve是否运作正常。

2) 提醒(Notification)

当被监控的某个 redis 服务器出现问题时, sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

3) 自动故障迁移(Automatic failover)

自动故障迁移是sentinel提供的最重要的功能,它保证了redis服务的HA。当一个主服务器不能正常工作时, sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

本文接下将分别阐释redis是如何实现上述3个功能的。

sentienl部署

redis sentinel 是一个分布式系统, 可以在一个系统中运行多个 sentinel 进程,为了提供保证服务的HA,一般建议部署3个以上的sentinel(不建议所有sentienl都部署在一台物理机器上)。

有了sentinel之后,redis服务中的角色就有了三种——master、salve、sentinel,某种角色在系统中都可以有多个。那么sentinel是如何实现和系统里的msater、salve、其他的sentinel进行信息交换的呢?我们先来看一下sentinel的配置,sentienl的配置非常简单,只需要修改sentinel.conf文件即可,且只需要在sentinel.conf中加入所有master即可。假设现在有3台master,IP地址分别为192.168.1.1192.168.1.2192.168.1.3,端口号统一为6379,那么sentinel.conf的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
port 26329

sentinel monitor master_1 192.168.1.1 6379 2
sentinel down-after-milliseconds master_1 2000
sentinel can-failover master_1 yes
sentinel parallel-syncs master_1 1
sentinel failover-timeout master_1 900000

sentinel monitor master_2 192.168.1.2 6379 2
sentinel down-after-milliseconds master_2 2000
sentinel can-failover master_2 yes
sentinel parallel-syncs master_2 1
sentinel failover-timeout master_2 900000

sentinel monitor master_3 192.168.1.3 6379 2
sentinel down-after-milliseconds master_3 2000
sentinel can-failover master_3 yes
sentinel parallel-syncs master_3 1
sentinel failover-timeout master_3 900000

从上述配置文件中我们可以看到,sentinel只配置了系统中所有master的信息,并没有配置salve和其他sentinel的信息,那么sentinel是如何监控这些slave的呢?sentinel是通过“自动发现”slave和其余sentinel来实现监控的。sentinel是通过master服务器来获得slave服务器的信息的,sentinel 通过向主服务器发送 INFO 命令来自动获得所有从服务器的地址。sentinel发现sentinel的过程则相对复杂。

在master和salve上有一个__sentinel__:hello 频道,每个 sentinel 会以每两秒一次的频率,向被它监视的所有主服务器和从服务器的 __sentinel__:hello 频道发送一条信息, 信息中包含了 sentinel 的 IP 地址、端口号和运行 ID (runid)。可以在master和slave上通过 PUBSUB CHANNELS 命令查看到__sentinel__:hello 频道:

此处输入图片的描述

每个 sentinel 都订阅了被它监视的所有主服务器和从服务器的 __sentinel__:hello 频道, 当有新的sentinel加入时,这个新的sentinel会向master的__sentinel__:hello 频道发送自己的信息。已存在的sentinel会接收到其订阅的 __sentinel__:hello 频道发来的新的sentinel的相关信息。当一个 sentinel 发现一个新的 sentinel 时, 它会将新的 sentinel 添加到一个列表中, 这个列表保存了 sentinel 已知的, 监视同一个主服务器的所有其他 sentinel。

在将一个新 sentinel 添加到监视主服务器的列表上面之前, sentinel 会先检查列表中是否已经包含了和要添加的 sentinel 拥有相同运行 ID 或者相同地址(包括 IP 地址和端口号)的 sentinel , 如果是的话, sentinel 会先移除列表中已有的那些拥有相同运行 ID 或者相同地址的 sentinel , 然后再添加新 sentinel 。

sentinel 发送的信息中还包括完整的主服务器当前配置(configuration)。 如果一个 sentinel 包含的主服务器配置比另一个sentinel发送的配置要旧, 那么这个 sentinel 会立即升级到新配置上。

一个 sentinel 可以与其他多个 sentinel 进行连接, 各个 sentinel 之间可以互相检查对方的可用性, 并进行信息交换。

在sentinel中可以通过 info 命令查看当前监控的master、slave、sentinel,如:

此处输入图片的描述

也可以通过sentinel master mastername查看监控的master服务器的状态:

此处输入图片的描述

sentinel定期任务

在本文开头我们提到过sentinel主要实现3个功能:监控,提醒,自动故障转移,那么sentinel是如何实现这些功能的呢?

每个 sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他sentinel发送一个 ping 命令。服务器对 ping 命令的有效回复可以是以下三种回复的其中一种:

1
2
3
返回 +PONG
返回 -LOADING 错误
返回 -MASTERDOWN 错误

如果服务器返回除以上三种回复之外的其他回复, 又或者在指定时间内没有回复 ping 命令, 那么 sentinel 认为服务器返回的回复无效(non-valid)。如果一个服务器距离最后一次有效回复 ping 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个服务器会被 sentinel 标记为主观下线

一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 sentinel 标记为主观下线。

比如 master-down-after-milliseconds 选项的值为 30000 毫秒(30 秒), 那么只要服务器能在每 29 秒之内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。

  • 主观下线(Subjectively Down, 简称 SDOWN)

单个 sentinel 实例对服务器做出的下线判断。当主服务器重新向 sentinel 的 ping 命令返回有效回复时, 服务器的主观下线状态就会被移除。

  • 客观下线(Objectively Down, 简称 ODOWN)

多个 sentinel 实例在对同一个服务器做出 SDOWN 判断后得出的服务器下线判断。

一个 sentinel 可以通过向另一个 sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。多个 sentinel 实例在对同一个服务器做出 SDOWN 判断后会得出一个结论,如果认定这个服务器下线了,那么这个服务器就是客观下线。

那么需要多少个sentinel对同一个服务器认定了主观下线这个服务器才会从主观下线状态切换到客观下线状态呢? 在redis中并没有使用严格的法定人数算法(strong quorum algorithm), 而是使用了流言协议((gossip protocols)):

如果 sentinel 在给定的时间范围内, 从其他 sentinel 那里接收到了足够数量的主服务器下线报告, 那么 sentinel 就会将服务器的状态从主观下线改变为客观下线。

当没有足够数量的 sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。

客观下线条件只适用于主服务器, 对于任何其他类型的 redis 实例(slave,sentinel), sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 sentinel 永远不会达到客观下线条件。

只要一个 sentinel 发现某个主服务器进入了客观下线状态, 这个 sentinel 就可能会被其他 sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。

sentinel 故障迁移(failover)

sentinel一次迁移转移操作由以下步骤组成:

(1) 发现主服务器已经进入客观下线状态

此处输入图片的描述

(2) 选举一个sentinel负责故障迁移(Raft leader election )

sentinel 自动故障迁移使用 Raft 算法来选举领头(leader)。 一个状态会以最后写入者胜出(last-write-wins)的方式(也即是,最新的配置总是胜出)传播至所有其他 sentinel 。举个例子, 当出现网络分割(network partitions)时, 一个 sentinel 可能会包含了较旧的配置, 而当这个 sentinel 接到其他 sentinel 发来的版本更新的配置时,sentinel 就会对自己的配置进行更新。

如果要在网络分割出现的情况下仍然保持一致性, 那么应该使用 min-slaves-to-write 选项, 让主服务器在连接的从实例少于给定数量时停止执行写操作, 与此同时, 应该在每个运行 Redis 主服务器或从服务器的机器上运行 redis sentinel 进程。

sentinel 状态的持久化 sentinel 的状态会被持久化在 sentinel 配置文件里面。每当 sentinel 接收到一个新的配置, 或者当领头 sentinel 为主服务器创建一个新的配置时, 这个配置会与配置纪元一起被保存到磁盘里面。这意味着停止和重启 sentinel 进程都是安全的。sentinel 在非故障迁移的情况下对实例进行重新配置即使没有自动故障迁移操作在进行, sentinel 总会尝试将当前的配置设置到被监视的实例上面。

(3) 选出一个从服务器,并将它升级为主服务器

此处输入图片的描述

sentinel 使用以下规则来选择新的主服务器:

1) 在失效主服务器属下的从服务器当中, 那些被标记为主观下线、已断线、或者最后一次回复 ping 命令的时间大于五秒钟的从服务器都会被淘汰。

2) 在失效主服务器属下的从服务器当中, 那些与失效主服务器连接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被淘汰。

3) 在经历了以上两轮淘汰之后剩下来的从服务器中, 3.1) 我们选出复制偏移量(replication offset)最大的那个从服务器作为新的主服务器; 3.2) 如果复制偏移量不可用, 或者从服务器的复制偏移量相同, 那么带有最小运行 ID 的那个从服务器成为新的主服务器。

(4) 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器

此处输入图片的描述

(5)通过发布与订阅功能, 将更新后的配置传播给所有其他 sentinel, 其他 sentinel对它们自己的配置进行更新

(6)向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器

此处输入图片的描述

当所有从服务器都已经开始复制新的主服务器时, 领头sentinel 终止这次故障迁移操作。

每当一个 redis 实例被重新配置(reconfigured) —— 无论是被设置成主服务器、从服务器、又或者被设置成其他主服务器的从服务器 —— sentinel 都会向被重新配置的实例发送一个 CONFIG REWRITE 命令, 从而确保这些配置会持久化在硬盘里。

Ref

Comments