1. Redis Sentinel
Sentinel
是哨兵的意思,Redis Sentinel
是Redis官方提供的高可用性的实现方案。
replication 模式下 master 与 slave 的自动切换
考虑以下场景,当 master 宕机,如何自动将 slave 选举为 master ?
Redis Sentinel为Redis提供高可用性。使用Sentinel可以创建一个Redis部署,在没有人为干预的情况下阻止某些类型的故障。
1.1. Sentinel功能的列表:
- 监控:Sentinel不断检查 master/slave 是否按预期工作。
- 通知:在Redis实例有异常的情况下,Sentinel可以通过API的方式通知系统管理员或其他响应处理程序。
- 自动故障切换:当master宕机后,Sentinel可以启动故障切换过程,在slave中自动选举一个新的master,通知其他的slave使用新的master,并且使用此master的应用程序在连接时会通知其使用新的master。
- 配置提供商:Sentinel为client提供配置信息:客户端连接到Sentinels,Sentinel为其提供当前的master服务地址。如果发生故障切换,Sentinels将报告新地址。
1.2. Sentinel是分布式的
Redis Sentinel本身也是一个分布式系统。
- 当多个哨兵都认为master不可用时才会执行故障检测,可以降低误报的可能性。
- 有Sentinel挂掉也不影响运行,提高容错性,防止单点故障。
1.3. 启动 Sentinel
对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:
redis-sentinel /path/to/sentinel.conf
对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:
redis-server /path/to/sentinel.conf --sentinel
两种方法都可以启动一个 Sentinel 实例。
启动 Sentinel 实例必须指定相应的配置文件, 系统会使用配置文件来保存 Sentinel 的当前状态, 并在 Sentinel 重启时通过载入配置文件来进行状态还原。
如果启动 Sentinel 时没有指定相应的配置文件, 或者指定的配置文件不可写(not writable), 那么 Sentinel 会拒绝启动。
1.4. 配置 Sentinel
Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
1.4.1. 配置参数
protected-mode no
默认情况下,sentinel不支持在localhost使用不同端口访问。可以通过配置
protected-mode no
禁用保护模式,或者使用bind
指令绑定127.0.0.1到其它IP:bind 127.0.0.1 192.168.1.1
port <sentinel-port>
sentinel端口,默认为26379,
port 26379
sentinel monitor <master-name> <ip> <redis-port> <quorum>
指示sentinel监视名为
master-name
的master,并确定最少要quorum
个sentinel同意才能判断该master失效。master-name
: 为要监控的master起一外名字, A-z 0-9 ".-_" 字符组成;ip
: master 的ipport
: master 的 端口quorum
: 判断master不可用需要多少个sentinel同意注意
- 只需要配置master监控,slave会自动发现,sentinels会自动重写此配置文件,添加slave信息;
- 当一个slave被选举为新的master的时候,此配置文件也会被自动重写;
- quorum的配置只是用来检测故障,并不会执行一次故障转移;如配置quorum为2,则有两个sentinel认定master无效时,即可认定master为无效,但不会选举新的master。
- 实际执行一次故障转移,必须选择一个sentinel作为故障转移领导者,并被授权执行,这需要超过半数的sentinel投票同意。这意味着,在故障期间,如果多数sentinel不能相互访问,则自动故障转移永远不会发生。
举个例子,有5个哨兵sentinels,quorum为2,那么:
- 如果有2个sentinel在同一时间认为master不可用,则可认定master不可用。
- 如果有3个sentinels可以相互访问,那么故障转移将被授权执行。
sentinel auth-pass <master-name> <password>
如果master设置了访问密码,可以使用此配置访问master和slave的密码
sentinel down-after-milliseconds <master-name> <milliseconds>
Sentinel 认为服务器已经断线所需的毫秒数,默认是30秒。
如果在给定的毫秒数之内,master没有对sentinel发送的PING命令进行回复,或者返回一个错误,那么sentinel将这个服务器标记为主观下线(subjectively down 简称SDOWN);
the time in milliseconds an instance should not be reachable (either does not reply to our PINGs or it is replying with an error) for a Sentinel starting to think it is down.
注意:只有一个sentinel将服务器标记为主观下线并不一定会引起服务器的故障迁移:只有在quorum个sentinel都将一个服务器标记为主观下线时,服务器才会被标记为客观下线(objectively down简称ODOWN),这时自动故障迁移才会执行。
sentinel parallel-syncs <master-name> <numslaves>
在执行故障转移时, 最多可以有多少个slave同时对新的master进行同步。这个数字越小,完成故障转移的时间就越长。
尽管复制过程的绝大部分步骤都不会阻塞slave服务器, 但slave服务器在载入master服务器发来的 RDB 文件时, 仍然会造成slave服务器在一段时间内不能处理命令请求: 如果全部slave服务器一起对新的master服务器进行同步, 那么就可能会造成所有slave服务器在短时间内全部不可用的情况出现。
可以通过将这个值设为 1 来保证每次只有一个slave服务器处于不能处理命令请求的状态。
1.4.2. 配置实例
运行一个 Sentinel 所需的最少配置如下所示:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
1.5. 每个 Sentinel 都需要定期执行的任务
- 每个 Sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。 一个有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
- 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有 Sentinel 要以每秒一次的频率确认主服务器的确进入了主观下线状态。
- 如果一个主服务器被标记为主观下线, 并且有足够数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。
- 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。 当一个主服务器被 Sentinel 标记为客观下线时, Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
- 当没有足够数量的 Sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向 Sentinel 的 PING 命令返回有效回复时, 主服务器的主管下线状态就会被移除。
1.6. 自动发现 Sentinel 和从服务器
一个 Sentinel 可以与其他多个 Sentinel 进行连接, 各个 Sentinel 之间可以互相检查对方的可用性, 并进行信息交换。
你无须为运行的每个 Sentinel 分别设置其他 Sentinel 的地址, 因为 Sentinel 可以通过发布与订阅功能来自动发现正在监视相同主服务器的其他 Sentinel , 这一功能是通过向频道 sentinel:hello 发送信息来实现的。
与此类似, 你也不必手动列出主服务器属下的所有从服务器, 因为 Sentinel 可以通过询问主服务器来获得所有从服务器的信息。
- 每个 Sentinel 会以每两秒一次的频率, 通过发布与订阅功能, 向被它监视的所有主服务器和从服务器的 sentinel:hello 频道发送一条信息, 信息中包含了 Sentinel 的 IP 地址、端口号和运行 ID (runid)。
- 每个 Sentinel 都订阅了被它监视的所有主服务器和从服务器的 sentinel:hello 频道, 查找之前未出现过的 sentinel (looking for unknown sentinels)。 当一个 Sentinel 发现一个新的 Sentinel 时, 它会将新的 Sentinel 添加到一个列表中, 这个列表保存了 Sentinel 已知的, 监视同一个主服务器的所有其他 Sentinel 。
- Sentinel 发送的信息中还包括完整的主服务器当前配置(configuration)。 如果一个 Sentinel 包含的主服务器配置比另一个 Sentinel 发送的配置要旧, 那么这个 Sentinel 会立即升级到新配置上。
- 在将一个新 Sentinel 添加到监视主服务器的列表上面之前, Sentinel 会先检查列表中是否已经包含了和要添加的 Sentinel 拥有相同运行 ID 或者相同地址(包括 IP 地址和端口号)的 Sentinel , 如果是的话, Sentinel 会先移除列表中已有的那些拥有相同运行 ID 或者相同地址的 Sentinel , 然后再添加新 Sentinel 。
1.7. 故障转移
一次故障转移操作由以下步骤组成:
- 发现主服务器已经进入客观下线状态。
- 对我们的当前纪元进行自增(详情请参考 Raft leader election ), 并尝试在这个纪元中当选。
- 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤。
- 选出一个从服务器,并将它升级为主服务器。
- 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。
- 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。
- 向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器。
- 当所有从服务器都已经开始复制新的主服务器时, 领头 Sentinel 终止这次故障迁移操作。 每当一个 Redis 实例被重新配置(reconfigured) —— 无论是被设置成主服务器、从服务器、又或者被设置成其他主服务器的从服务器 —— Sentinel 都会向被重新配置的实例发送一个 CONFIG REWRITE 命令, 从而确保这些配置会持久化在硬盘里。
Sentinel 使用以下规则来选择新的主服务器:
- 在失效主服务器属下的从服务器当中, 那些被标记为主观下线、已断线、或者最后一次回复 PING 命令的时间大于五秒钟的从服务器都会被淘汰。
- 在失效主服务器属下的从服务器当中, 那些与失效主服务器连接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被淘汰。
- 在经历了以上两轮淘汰之后剩下来的从服务器中, 我们选出复制偏移量(replication offset)最大的那个从服务器作为新的主服务器; 如果复制偏移量不可用, 或者从服务器的复制偏移量相同, 那么带有最小运行 ID 的那个从服务器成为新的主服务器。