《Redis开发与运维》读书笔记(九)哨兵

第九章 哨兵

主从复制模式下,一旦主节点故障,需要手动晋升从节点,还要通知应用更新主节点地址。Redis 2.8版本提供Sentinel(哨兵)架构来解决该问题。

9.1 基本概念

名称解释:

名词 逻辑结构 物理结构
主节点 Redis主服务/数据库 一个独立的Redis进程
从节点 Redis从服务/数据库 一个独立的Redis进程
Redis数据节点 主节点和从节点 主节点和从节点的进程
Sentinel节点 监控Redis数据节点 一个独立的Sentinel进程
Sentinel节点集合 若干Sentinel节点的抽象组合 若干Sentinel节点进程
Redis Sentinel Redis高可用实现方案 Sentinel节点集合和Redis数据节点进程
应用方 泛指一个或多个客户端 一个或多个客户端进程或者线程

9.1.1 主从复制的问题

主从复制的作用:

  1. 数据一致性:在主节点故障时顶上,并保证数据不丢失。
  2. 读写分离:扩展主节点的读能力,分摊并发读压力。

问题:

  • 主节点故障,从节点需要手动晋升,还要修改应用方的主节点地址,还要命令其他从节点复制新的主节点。
  • 主节点的写能力受到单机限制。
  • 主节点的存储能力受到单机限制。

9.1.2 高可用

一主二从模式下如何进行故障转移:

  1. 主节点故障,客户端连接失败,主从节点连接失败导致复制中断。

  2. 主节点无法启动,需要选出一个从节点,执行 slaveof no one 使其成为主节点。

  3. 更新应用的主节点信息,重启应用。

  4. 客户端命令另一个从节点复制新的主节点。

  5. 待原来的主节点恢复后,让其复制新的主节点。

故障转移过程需要人工介入,整理非高可用,即使将人工过程自动化,还是有问题:

  1. 判断节点不可达机制是否健全和标准。
  2. 如果多个从节点、,如何保证只有一个被晋升为主节点。
  3. 通知客户端的新的主节点机制是否足够健壮。

9.1.3 Redis Sentinel的高可用性

  • Sentinel能够自动完成故障发现和故障转移,并通知应用方来实现高可用。
  • Sentinel是一个分布式架构,包含若干Sentinel节点和Redis数据节点,每个Sentinel节点会对数据节点和其它Sentinel节点进行监控,当发现节点不可达时,会标记下线标识。如果被标识的是主节点,还会和其它Sentinel节点协商,当大部分Sentinel节点都认为主节点不可达时,会选举出一个Sentinel节点来完成自动故障转移工作,同时将变化通知给应用。

Sentinel相比主从复制从结构上只是多了若干Sentinel节点,并没有对Redis节点做特殊处理。

举例说明,1个主节点,2个从节点,3个Sentinel节点。

故障转移处理逻辑:

  1. 主节点出现故障,主从节点失去连接,主从复制失败。

  2. 每个Sentinel节点通过定期监控发现主节点出现故障。

  3. 多个Sentinel节点对主节点的故障达成一致,选举出Sentinel-3节点作为Leader负责故障转移。

  4. Sentinel领导者节点执行了故障转移,转移流程与主从复制一致,只不过全程是自动化的。

  5. 故障转移后整个Sentinel的拓扑结构:

Sentinel的功能:

  • 监控:Sentinel节点会定期检测数据节点、其余Sentinel节点是否可达。

  • 通知:Sentinel节点会将故障转移的结果通知给应用方。

  • 主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系。

  • 配置提供者:客户端初始化时连接的是Sentinel节点集合,从中获取主节点信息。

    多个Sentinel节点的优点:

    • 对于节点的故障判断是多个节点共同完成,防止误判。
    • 防止个别Sentinel节点不可用,整体集合是健壮的。

9.2 安装和部署

9.2.1 部署拓扑结构

案例拓扑结构:

物理结构:

9.2.2 部署Redis数据节点

该过程并无特殊配置。

(1)启动主节点

配置:

1
2
3
4
5
port 6379
daemonsize yes
logfile "6379.log"
dbfilename "dump-6379.rdb"
dir "/opt/soft/redis/data"
1
2
3
$ redis-server redis-6379.conf
# 确定是否启动
$ redis-cli -h 127.0.0.1 -p 6379 ping

(2)启动两个从节点

1
2
3
4
5
6
port 6380
daemonsize yes
logfile "6380.log"
dbfilename "dump-6380.rdb"
dir "/opt/soft/redis/data"
slaveof 127.0.0.1 6379
1
2
$ redis-server redis-6380.conf
$ redis-server redis-6381.conf

(3)确认主从关系

1
2
3
4
5
6
7
8
9
10
11
12
$ redis-cli -h 127.0.0.1 -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=......
slave1:ip=......
$ redis-cli -h 127.0.0.1 -p 6380 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up

9.2.3 部署Sentinel节点

三个Sentinel节点的部署方法一致。

(1)配置

1
2
3
4
5
6
7
8
9
port 26379
daemonsize yes
logfile "26379.log"
dbfilename "dump-26379.rdb"
dir "/opt/soft/redis/data"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mtmaster 180000
  • sentinel节点默认端口为26379
  • sentinel节点监控6379主节点,2表示判断主节点失败至少需要2个sentinel节点同意

(2)启动

1
2
3
# 两种启动方法
$ redis-sentinel redis-sentinel-26379.conf
$ redis-sentinel redis-sentinel-26379.conf --sentinel

(3)确认

通过info命令来查看sentinel节点的信息,sentinel节点能够彼此感知到。

1
$ redis-cli -h 127.0.0.1 -p 26379 info Sentinel
  • 生产环境建议sentinel节点分布在不同物理机。

9.2.4 配置优化

Redis安装目录下的sentinel.conf是默认配置文件。

(1)配置说明和优化

  • port:Sentinel节点端口。

  • dir:Sentinel节点工作目录。

  • sentinel monitor <matser-name> <ip> <port> <quorum> :监控一个名字叫matser-name并配置地址的主节点,quorum表示要判定主节点不可达需要的票数(一般建议设置为Sentinel节点数一半加一)。实际上Sentinel节点会对所有节点进行监控,却没有配置其它节点,因为可以从主节点获取其余节点相关信息。

    1
    2
    3
    4
    5
    6
    7
    # 启动后:
    # 发现两个slave节点
    sentinel known-slave mymaster 127.0.0.1 6380
    sentinel known-slave mymaster 127.0.0.1 6381
    # 发现两个sentinel节点
    sentinel known-sentinel mymaster 127.0.0.1 26380 ......
    sentinel known-sentinel mymaster 127.0.0.1 26381 ......

    至少有max(quorum, num(sentinels) / 2 + 1)个节点参与选举才可以选出Leader,最终完成故障转移。

  • sentinel down-after-milliseconds <master-name> <times> :每个sentinel节点需要定期发送ping命令来判断数据节点和其余sentinel节点是否可达,超过该配置时间没有有效回复就判定为不可达。该配置太大就会导致过于宽松,故障时间增长,过小会导致一定的误判率。

  • sentinel parallel-syncs <master-name> <nums> :限制在一次故障转移后,每次向新主节点发起复制操作的从节点个数。参数设置较大时,会有多个从节点同时发起复制操作,造成主节点机器一定的网络和磁盘开销。

  • sentinel failover-timeout <master-name> <times> :故障转移超时时间。

    作用阶段:

    • a:选出合适从节点。
    • b:晋升选出的从节点为主节点。
    • c:命令其余从节点复制新的主节点。
    • d:等待原主节点恢复后命令它去复制新的主节点。

    作用:

    1. 如果对一个主节点的故障转移失败,下次开始的时间是该配置的2倍。
    2. b阶段,如果Sentinel节点向a阶段选出的从节点执行slaveof no one一直失败,超时则转移失败。
    3. b阶段执行成功,Sentinel节点会执行info命令来确认a阶段选出的节点是否晋升为主节点,超时则转移失败。
    4. c阶段执行时间超过failover-timeout(不包含复制时间),则转移失败。
  • sentinel auth-pass <master-name> <password> :通过添加主节点密码防止Sentinel节点无法监控主节点。

  • sentinel notification-script <master-name> <script-path> :在故障转移期间,当一些警告级别的Sentinel事件发生(如-sdown:客观下线、-odown:主观下线)时,触发对应路径的脚本,并向脚本发送相应的事件参数。

    如在 /opt/redis/scripts 下配置了 notification.sh,脚本会接收每个Sentinel节点传过来的事件参数,利用这些可以作为邮件或短信报警的依据。

    1
    2
    3
    4
    5
    # !/bin/sh
    # 获取所有参数
    msg=$*
    # 报警脚本或接口,将msg作为参数
    exit 0

    如果需要此功能,可以在Sentinel节点添加如下配置:

    1
    $ sentinel notification-script mymaster /opt/redis/scripts/notification.sh
  • sentinel client-reconfig-script <master-name> <script-path> :在故障转移结束后,触发对应路径的脚本,并向脚本发送故障转移结果相关参数。

    如果需要此功能,可以在Sentinel节点添加如下配置:

    1
    $ sentinel client-reconfig-script mymaster /opt/redis/scripts/client-reconfig.sh

    发送故障转移结果的相关参数:

    • master-name:主节点名
    • role:角色,包括Leader和Observer,前者负责了故障转移。
    • from-ip:原主节点的ip地址。
    • from-port:原主节点的端口。
    • to-ip:新主节点的ip地址。
    • to-port:新主节点的端口。

script注意:

  • script-path必须有可执行权限。
  • script-path开头必须包含shell脚本头,如 #!/bin/sh ,否则事件产生时,Redis将无法执行脚本产生错误 -script-error /opt/sentinel/notification.sh 0 2
  • 脚本的最大执行时间不能超过60秒,超过会被kill。
  • 若脚本以exit 1结束,那么脚本稍后重试执行。若以exit 2或更高值结束,则不会重试。正常返回值为0。
  • 如果需要运维的Sentinel较多,尽量不要以脚本形式通知,增加部署的成本。

(2)如何监控多个主节点

Sentinel可以同时监控多个主节点,配置时指定多个masterName即可。

1
2
3
4
5
6
7
8
sentinel monitor master-business-1 10.10.XX.1 6379 2
sentinel down-after-milliseconds master-business-1 60000
sentinel parallel-syncs master-business-1 1
sentinel failover-timeout master-business-1 180000
sentinel monitor master-business-2 10.16.XX.2 6380 2
sentinel down-after-milliseconds master-business-2 10000
sentinel parallel-syncs master-business-2 1
sentinel failover-timeout master-business-2 180000

(3)调整配置

Sentinel支持动态设置参数:

1
$ sentinel set <param> <value>

注意点:

  1. set命令只对当前Sentinel节点有效。
  2. set命令如果执行成功会立即刷新配置文件,这与Redis普通数据节点设置配置需要执行config rewrite刷新到配置文件不同。
  3. 建议所有的Sentinel节点配置尽可能一致,这样在故障发现和转移时比较容易达成一致。
  4. set支持的参数可以参考源码中sentinel.c的sentinelSetCommand函数。
  5. Sentinel对外不支持config命令。

9.2.5 部署技巧

  1. Sentinel节点不应该部署在同一台机器上。
    • 即使使用虚拟机或容器技术分配了不同的IP地址,会同时受硬件故障影响。
  2. 部署至少三个且奇数个Sentinel节点。
    • 3个以上是为了提高故障判定的准确性。
    • 因为选举需要至少一半加1个节点,奇数个节点可以在满足该条件基础上节省一个节点。
  3. 只有一套Sentinel还是每个主节点都要配一套Sentinel?
    • 方案一:降低了维护成本,但当Sentinel节点集合出现异常,可能会多个Redis数据节点造成影响。如果监控的节点个数过多,会造成Sentinel节点产生过多的网络连接。
    • 方案二:造成了资源浪费,但每套Sentinel集合彼此隔离。


9.3 API

(1)sentinel masters

显示所有被监控的主节点状态和相关信息:

1
$ sentinel masters

(2)sentinel master <master name>

显示指定主节点状态和相关信息:

1
$ sentinel master mymaster1

(3)sentinel slaves <master name>

显示指定从节点状态和相关信息:

1
$ sentinel slaves mymaster1

(4)sentinel sentinels <master name>

显示指定Sentinel节点集合,不包含当前Sentinel节点:

1
$ sentinel sentinels mymaster1

(5)sentinel get-master-addr-by-name <master name>

返回指定的主节点的IP地址和端口:

1
$ sentinel get-master-addr-by-name mymaster1

(6)sentinel reset <pattern>

当前Sentinel节点对符合pattern主节点配置进行重置,包括清除主节点状态(包括故障转移),重新发现从节点和Sentinel节点。

(7)sentinel failover <master name>

对指定主节点进行强制故障转移(不经过Sentinel协商),完成后,其他Sentinel节点按照转移结果更新自身配置。

(8)sentinel ckquorum <master name>

检测当前可达的Sentinel节点总数是否达到quorum个数,如果节点个数小于quorum就无法进行故障转移。

(9)sentinel flushconfig

将Sentinel节点的配置强制刷新到硬盘上,只有如磁盘损坏等外部原因导致配置文件损坏或丢失时,才会使用这个命令。

(10)sentinel remove <master name>

取消当前Sentinel节点对于指定主节点的监控。该命令仅对当前Sentinel节点有效。

(11)sentinel monitor <master name> <ip> <port> <quorum>

通过命令形式完成对主节点的监控。

1
$ sentinel monitor mymaster1 127.0.0.1 6379 2

(12)sentinel set <master name>

动态修改Sentinel节点配置选。

(13)sentinel is-master-down-by-addr

Sentinel节点之间用来交换对主节点是否下线的判断,根据参数不同,可以作为Sentinel领导者选举的通信方式。


9.4 客户端连接

相比主从复制,Sentinel需要各个语言的客户端显式的支持,否则无法感知到状态变化。

9.4.1 Redis Sentinel的客户端

主节点通过<master name>进行标识,正确连接Redis Sentinel需要有Sentinel集合和masterName两个参数。

9.4.2 Redis Sentinel客户端基本实现原理

实现一个Sentinel客户端的基本步骤:

  1. 遍历Sentinel节点集合,找到一个可用的节点。

  2. 通过sentinel get-master-addr-by-name <master name> 获取对应主节点相关信息。

  3. 验证当前获取的主节点是否是真正的主节点,防止故障转移期间主节点发生变化。

  4. 保持和Sentinel节点集合的联系,即刻获取有关主节点的相关信息。

只有初始化和主节点切换时需要进行交互,所以设计客户端时需要将Sentinel集合考虑成配置发现服务。

9.4.3 Java操作Redis Sentinel

Jedis构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public JedisSentinelPool(String masterName,
Set<String> sentinels,
final GenericObjectPoolConfig poolConfig,
final int connectionTimeout,
final int soTimeout,
final String password,
final int database,
final String clientName) {
// 初始化过程:
...
HostAndPort master = initSentinels(sentinels, masterName);
initPool(master);
...
}

......
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
// jedis command
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
} finally {
if (jedis != null)
jedis.close();
}
  • masterName:主节点名。
  • sentinels:节点集合。
  • poolConfig:连接池配置。
  • connectionTimeout:连接超时。
  • soTimeout:读写超时。
  • password:主节点密码。
  • database:数据库索引。
  • clientName:客户端名。

  1. 遍历所有Sentinel节点集合,找到一个可用的节点,如果找不到则抛出异常 new JedisException("Can connect to sentinel, but" + masterName + " seems to be not monitored...")

  2. 找到可用的Sentinel节点,执行sentinelGetMasterAddrByName(masterName),找到对应主节点信息。

  3. JedisSentinelPool中没有发现对主节点角色验证的代码,因为get-master-addr-by-name这个API会自动获取真正的主节点。

  4. 为每一个Sentinel节点单独启动一个线程, 利用发布订阅功能,每个线程订阅Sentinel节点上切换master相关频道+switch-master。

    1
    2
    3
    4
    for (String sentinel : sentinels) {
    final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
    MasterListener masterListener = new MasterListener(masterName, hap.masterListener.start());
    }

    订阅Sentinel节点的 +switch-master 频道:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Jedis sentinelJedis = new Jedis(sentinelHost, sentinelPort);
    // 客户端订阅Sentinel节点上+switch-master频道
    sentinelJedis.subscribe(new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
    String[] switchMasterMsg = message.split(" ");
    if (switchMasterMsg.length > 3) {
    // 判断是否为当前masterName
    if (masterName.equals(switchMasterMsg[0])) {
    // 发现当前masterName发送switch,使用initPool重新初始化连接池
    initPool(toHostAndPort(switchMasterMsg[3], switchMasterMsg[4]));
    }
    }
    }
    }, "+switch-master");

9.5 实现原理

9.5.1 三个定时监控任务

通过三个定时监控任务来完成对每个节点的发现和监控:

  1. 每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新拓扑结构。

    作用:

    • 通过向主节点执行info命令,获取从节点信息,这也是为什么Sentinel节点不用显式配置从节点监控。
    • 当有新的从节点加入时可以立即感知。
    • 节点不可达或故障转移后,可以实时更新拓扑信息。
  2. 每隔2秒,每个Sentinel节点会向数据节点的 _sentinel_:hello 频道发送该Sentinel节点对于主节点的判断以及当前Sentinel节点信息。Sentinel节点通过该频道获取各自对主节点的判断。

    作用:

    • 发现新的Sentinel节点:通过订阅主节点的该频道了解其他Sentinel节点信息,如果是新加入的Sentinel节点,将其保存起来并创建连接。

    • Sentinel节点之间交换主节点状态,作为后面客观下线以及Leader选举的依据。publish的消息格式:

      1
      <Sentinel节点IP> <Sentinel节点端口> <Sentinel节点runId> <Sentinel节点配置版本> <主节点名字> <主节点IP> <主节点端口> <主节点配置版本>
  3. 每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确定这些节点当前是否可达。该任务是判断节点失败的重要依据。

9.5.2 主观下线和客观下线

  • 主观下线:当节点超时没有回复心跳检测,Sentinel节点做出失败判定。主观下线是一家之言,存在误判可能。从节点和Sentinel节点在主观下线后,没有后续的故障转移操作。

  • 客观下线:当Sentinel主观下线的节点是主节点时,需要通过 sentinel is-master-down-by-addr 命令询问其他Sentinel节点的判断。超过quorum个数后就认为该主节点确实有问题。

sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>

  • ip:主节点IP。
  • port:主节点端口。
  • current_epoch:当前配置纪元。
  • runid:两种类型:
    1. runid等于*,作用是Sentinel节点直接交换对主节点下线的判定。
    2. runid等于当前Sentinel节点的runid,作用是当前Sentinel节点希望目标Sentinel节点同意自己成为Leader的请求。

返回:

  • down_state:目标Sentinel节点对于主节点的下线判定,1为下线,0为在线。
  • leader_runid:等于*时,表示用来做主节点是否不可达;等于具体runid时,表示目标节点同意runid成为Leader。
  • leader_epoch:领导者纪元。

9.5.3 领导者Sentinel节点选举

客观下线后是否会立即进行故障转移?当然不是,故障转移工作其实只需一个Sentinel节点即可完成。Sentinel节点间会进行Leader选举,选中的节点进行故障转移工作。Redis使用Raft算法实现Leader选举(内容参考分布式事务中Paxos相关内容),大致流程:

  1. 每个Sentinel节点都有机会成为Leader,当确认主节点客观下线时,会向其他Sentinel节点发送 is-master-down-by-addr 命令,要求将自己设置为Leader。
  2. 收到命令的Sentinel节点,如果没有同意其他Sentinel节点则会同意,否则拒绝。
  3. 当Sentinel节点票数大于 max(quorum, num(sentinels) / 2 + 1) 就会成为Leader。
  4. 此过程若没有产生Leader,会进入下次选举。

9.5.4 故障转移

Leader节点负责故障转移:

  1. 在从节点列表中选出一个节点作为新的主节点,判断方法:
    • 过滤不健康的节点:主观下线、断线、5秒内没有回复过PING、与主节点失联超过down-after-millseconds*10秒。
    • 选择slave-priority最高的从节点列表,存在则返回,否则继续。
    • 选择复制偏移量最大的从节点,复制的最完整,存在则返回,否则继续。
    • 选择runid最小的从节点。
  2. Leader节点对第一步选出的从节点执行 slaveof no one 命令让其成为主节点。
  3. Leader节点向剩余从节点发送命令,使其成为新主节点的从节点,复制规则和parallel-syncs参数有关。
  4. Sentinel节点集合会将原来的主节点更新为从节点,并保持关注,当期恢复后命令其复制新的主节点。


9.6 开发与运维中的问题

9.6.1 故障转移日志分析

(1)Redis Sentinel 拓扑结构

(2)开始故障转移测试

模拟方法:

  1. 强制kill对应节点的进程号,模拟宕机的效果。
  2. 使用Redis的debug sleep命令,让节点进入睡眠状态,模拟阻塞的效果。
  3. 使用Redis的shutdown命令,模拟正常停掉节点。

使用方法一:

1
$ kill -9 19661

(3)观察效果

6380晋升为主节点,6381成为6380的从节点。

(4)故障转移分析

6379节点日志

两个复制请求,分别来自6380和6381从节点。09:40:35做了kill操作,6379无法看到相关日志。

6380节点日志

kill后已和6379失联。

09:41:06时收到Sentinel节点命令,清理原来缓存的主节点状态,6380被晋升为主节点,重写配置。

6381发来了复制请求:

6381节点日志

同样与6379失联。

后续操作:

  1. 09:41:06时收到Sentinel节点命令,清理主节点状态,复制6380主节点。

  2. 向新的主节点发起复制操作。

sentinel-1节点日志

09:41:05对6379做了主观下线,正好是kill -9后的30秒,与down-after-milliseconds一致。Sentinel节点更新自己的配置纪元:

后续操作:

  1. 投票给sentinel-3节点:

  2. 更新状态:从sentinel-3节点得知,故障转移后6380变为主节点,并发现两个从节点6381和6379,并在30秒后对(09:41:07 ~ 09:41:37)6379做了主观下线。

sentinel-2节点日志

整个过程和sentinel-1节点一致。

sentinel-3节点日志
  1. 达到了客观下线的条件:

  2. sentinel-3节点被选为Leader。

    sentinel-3节点最先完成客观下线。

  3. 故障转移。每一步都可以通过发布订阅获取,寻找合适的从节点作为新的主节点:

<instance details>格式如下:

1
<instance details> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

(5)原主节点后续处理

重新启动原来的6379节点:

1
2
redis-server redis-6379.conf
操作时间:2016-07-24 09:46:21
6379节点

启动后收到Sentinel节点命令,复制6380节点:

6380节点

接到6379节点的复制请求,相应处理:

sentinel-1节点

撤销对6379节点主观下线的决定。

sentinel-2节点

撤销对6379节点主观下线的决定。

sentinel-3节点

撤销对6379节点主观下线的决定,更新Sentinel节点配置。

(6)注意

各个节点的机器时间要尽量同步,否则日志时序性会混乱,可以给机器加NTP服务来同步时间。

9.6.2 节点运维

(1)节点下线

  • 临时下线:暂时关掉,之后还会重新启动,继续提供服务。
  • 永久下线:节点关闭后不再使用,需要一些清理工作,如删除配置文件、持久化文件和日志文件。

下线原因:

  • 节点不稳定或即将过保被回收。
  • 节点机器性能较差或内存较小,无法支撑需求。
  • 节点自身出现服务不正常情况,需要快速处理。
主节点

任意可用的Sentinel节点执行:

1
$ sentinel failover <master name>

从节点和Sentinel节点

确定是临时还是永久下线并执行即可。若使用了读写分离,下线从节点需要保证应用方可以感知从节点的下线变化,从而把读取请求路由到其他节点。节点下线后,Sentinel仍会定期进行监控。

(2)节点上线

添加从节点

常见场景:

  • 使用了读写分离,但现有从节点无法支撑应用方的流量。
  • 主节点没有可用的从节点,无法支持故障转移。
  • 添加一个更强的从节点利用failover替换主节点。

添加 slaveof {masterIp} {masterPort} 的配置,使用redis-server启动即可,会被Sentinel自动发现。

添加Sentinel节点

场景:

  • 当前Sentinel节点数量不够,无法达到健壮性要求或者无法达到票数。
  • 原Sentinel节点所在机器需要下线。

添加 sentinel monitor 主节点配置,使用redis-sentinel启动即可,可以使用failover节点自动发现。

添加主节点

因为Sentinel只能有一个主节点,所以不需要添加主节点,如果需要替换主节点,可以使用failover手动故障转移。

(3)节点配置

要注意的点:

  • Sentinel节点配置尽可能一致,判断故障时更准确。
  • Sentinel节点支持命令有限,如需修改配置,重新启动即可。

9.6.3 高可用读写分离

(1)从节点的作用

作用:

  1. 当主节点出现故障,作为备用实现故障转移,Sentinel实现了该过程的自动化,实现了真正的高可用。
  2. 扩展主节点的读能力,尤其是读多写少的场景。

如图模型,从节点不是高可用,一旦发生故障,客户端会首先与其失联,其次Sentinel节点对其主观下线。因为Sentinel的故障转移是针对主节点的,从节点仅仅作为主节点一个热备,不会参与客户端的读操作,就是为了保证整体高可用性。

Redis Sentinel中的从节点仅仅是作为主节点一个热备,不让它参与客户端的读操作,就是为了保证整体高可用性。但实际上这种使用方法,还是有一些浪费,尤其是在很多从节点确实需要读写分离的场景,如何实现从节点的高可用是非常有必要的。

(2)Redis Sentinel 读写分离的设计思路

Redis Sentinel 在对各个节点的监控,如果有对应事件的发生,都会发出相应的事件消息。

  • +switch-master:切换主节点(原来从节点晋升主节点),说明减少了某个从节点。
  • +convert-to-slave:切换从节点(原来的主节点降级为从节点),说明添加了某个从节点。
  • +sdown:主观下线,说明可能某个从节点可能不可用(从节点不会做客观下线),所以在实现客户端时可以采用自身策略来实现类似主观下线的功能。
  • +report:重新启动了某个节点,如果它的角色是slave,那么说明添加了某个从节点。

只要掌握了从节点的状态,将所有从节点看作一个资源池,无论是上下线从节点,客户端都能感知到。


参考:

🔗 《Redis开发与运维》