14. 哨兵

master宕机

如果主从模式下的master宕机,一般处理流程:

  1. 将宕机的master下线
  2. 找一个slave作为master
  3. 通知所有的slave连接新的master
  4. 启动新的master与slave
  5. 全量复制*N + 部分复制*N

出现的问题:

  • 谁来确认master宕机了
  • 选新的master如何选?
  • 修改配置后,原来的master恢复了怎么办?

哨兵

哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

作用:

  • 监控

不断的检查master和slave是否正常运行。

master存活检测、master与slave运行情况检测

  • 通知(提醒)

当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知

  • 自动故障转移

断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址。

哨兵也是一台redis服务器,只是不提供数据服务。

通常哨兵配置数量为单数。

哨兵搭建示例

配置哨兵(参考 sentinel.conf 配置文件)

编写配置文件sentinel-端口号.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
port 26379
daemonize no
pidfile /var/run/redis-sentinel.pid
logfile ""
dir /tmp
# sentinel monitor [自定义的名称] 监控的master的ip和端口 判断master宕机的哨兵数量
# 如果有2台哨兵认为master宕机了,master就下线
sentinel monitor mymaster 127.0.0.1 6379 2
# master判定宕机的未响应时长(单位毫秒)
sentinel down-after-milliseconds mymaster 30000
# 新的master上来之后,进行数据同步时,一次多少个数据开始同步
sentinel parallel-syncs mymaster 1
# 多久未同步完成算作超时(单位毫秒)
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes

启动哨兵:

1
redis-sentinel sentinel-端口号.conf

使用客户端连接时,依然是redis-cli启动客户端,但是不允许使用setget等指令。

哨兵启动之后,刚刚编写的配置文件会被自动重写一部分,例如变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel.pid"
logfile "26379.log"
dir "/home/redis/data"
sentinel myid d957acd3913031c3bec970b13f9a2cc446230d25
sentinel deny-scripts-reconfig yes
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
# Generated by CONFIG REWRITE
protected-mode no
maxclients 4064
user default on nopass ~* +@all
sentinel known-replica mymaster 127.0.0.1 6381
sentinel known-replica mymaster 127.0.0.1 6380
sentinel known-sentinel mymaster 127.0.0.1 26380 5b8d465eba4e61f72f245cc12d32d4c45b812ae5
sentinel known-sentinel mymaster 127.0.0.1 26381 8812ba72638e42fbbc1a9af8a8a2e1716e223011
sentinel current-epoch 0

工作原理

三个阶段:

  • 监控

同步信息

  • 通知

保持连通

  • 故障转移

发现问题

选择竞选负责人

优选新的master

新master上任,其他slave切换master,原master改为slave

监控阶段

同步各个节点的状态信息

  • 通过ping指令获取各个sentinel的状态(是否在线)
  • 通过info指令获取master的状态
    • master的属性:runid、role:master
    • 各个slave的详细信息
  • 通过info获取所有slave的状态(根据master中的slave信息)
    • slave的属性:runid、role:slave、master_host、master_port、offset.....
1
2
3
4
5
6
7
8
9
10
11
12
13
sentinel[1]->master: 发送指令:info \n 获取master状态
sentinel[1]->master: 建立cmd连接
note right of master: master记录的信息:\n master信息\nslaves信息\n当前master连接的sentinels
note left of sentinel[1]: sentinel[1]记录的信息:\nmaster信息\nslaves信息\n当前master连接的sentinels
note left of sentinel[1]: sentinel[1]向slaves发送info指令,\n获取slaves状态
# 此时又增加了一台哨兵 sentinel[2]
sentinel[2]->master: 发送指令:info
sentinel[2]->master: 建立cmd连接
note right of master: master更新记录的信息:\n当前master连接的sentinels
note right of sentinel[2]: sentinel[2]记录的信息:\nmaster信息\nslaves信息\n当前master连接的sentinels
note right of sentinel[2]: sentinel[2]向slaves发送info指令,\n获取slaves状态
sentinel[2]->sentinel[1]: 建立通道:publish / subscribe \n用于哨兵间数据同步
sentinel[1]->sentinel[2]: 发送指令:ping \n获取各个sentinel状态

通知阶段

1
2
3
sentinel[1]->master/slaves: publish sentnel: hello
master/slaves->sentinel[1]: 返回状态信息
note left of sentinel[1]: 在哨兵间的publish/subscribe网络中\n发布master/slaves的状态信息

故障转移阶段

确认master下线流程:

1
2
3
4
5
6
7
sentinel[1]->master: 发送hello指令无响应
sentinel[1]->master: 连续发送hello指令
note left of sentinel[1]: sentinel[1]将master标记为:SRI_S_DOWN \n S_DOWN:主观下线
sentinel[1]->sentinel[2]: 通过哨兵间的发布/订阅通道\n向其他哨兵传播master下线信息\n SENTINEL is-master-down-by-addr\n服务器host,port,发起方,状态....
sentinel[2]->master: 向master连续发送hello指令
sentinel[2]->sentinel[1]: sentinel[2]通过哨兵间发布/订阅通道\n确认master下线信息
note right of sentinel[2]: 超过一定数量的哨兵认为master下线\n(数量在哨兵配置文件配置)\nmaster被标记为:SRI_O_DOWN\nO_DOWN:客观下线

投票选择哨兵间的leader:

每个哨兵向哨兵间发布/订阅通道内发送信息:

SENTINEL is-master-down-by-addr ....

  • 下线的master的ip
  • 下线的master的端口号
  • 哨兵自己参与哨兵leader竞选的次数
  • 哨兵自己的runid

每一个哨兵作为参选者,同时也是投票者,每个哨兵有一票。哨兵根据自己接收到其他哨兵发送信息的先后顺序,把自己的票投给对应的哨兵。最终汇总得票结果,选出哨兵leader。如果第一轮没有选出来leader,再进行一轮投票,直至得出哨兵leader。每增加一轮,哨兵的参与竞选次数会增加1。

哨兵leader 从slave服务器里列表中挑选备用master转正,选择的原则:

  1. 备选的slave需要是在线的
  2. 给slave不停发送hello消息,淘汰掉响应慢的
  3. 淘汰与原master断开时间久的
  4. 优先原则
    • 比较优先级
    • 比较数据同步的offset
    • 选择runid比较小的

哨兵leader发送指令告知新的master:

  • 向新的master发送slaveof no one 指令
  • 向其他slave发送slaveof 新master的ip 端口号

14. 哨兵
http://binbo-zappy.github.io/2024/12/07/Redis/14-哨兵/
作者
Binbo
发布于
2024年12月7日
许可协议