在主从模式的基础上提供高可用,在master宕机情况下自动切换slave为master,当旧的master重新连接后哨兵会将其转为新master的slave;

相关的知识:

  • 哨兵有3个定时任务:

1、每隔10s,哨兵会向master和slave发送INFO命令,用于获取主从结构和探测发现slave;

2、每隔2s,哨兵会向__sentinel__:hello频道发布订阅消息,消息包含对master的认知和自身信息,其他哨兵通过订阅获得该消息;

3、每隔1s,哨兵会发送ping心跳给master、slave、其他哨兵,用于判断其他成员的主观下线;

  • 主观下线 SDOWN:

每隔1s的ping在超过down-after-milliseconds设置的时间后没有收到回复或回复错误,则认定该成员主观下线;(如果master又有了正确的ping回复,则主观下线状态会被移除)

  • 客观下线 ODOWN:(master才有)

当master主观下线时,哨兵会询问其他哨兵master的状态,如果达到<quorum>个哨兵也认为下线,才会认为master客观下线;(如果没有达到<quorum>个则不会客观下线,只有master客观下线才可以进行故障转移)

  • 故障转移流程:

哨兵每秒发送ping心跳;心跳超过down-after-milliseconds没有回复或回复错误,认为主观下线;如果master主观下线,则询问其他哨兵master状态,达到<quorum>个哨兵也认为master下线,则标记master为客观下线;最先完成master客观下线的哨兵发起leader选举,通过Raft协议最终选举出一个leader;由leader发起故障转移,选出slave中优先级高复制最完整的一个升级为新master,宕机master降为slave(哨兵会持续关注宕机master,连接后让宕机master变为slave去同步当前的新master),通知其他slave连接新的master,并通知其他哨兵主从变化;

当前redis版本5.0.4;

哨兵使用的sentinel.conf的配置项:(使用默认文件修改,用过的文件会被哨兵修改)(更新至v7.0.2版本)

  • bind 127.0.0.1 192.168.1.1
  • protected-mode no

默认哨兵只能由localhost访问,也可以通过bind手动绑定地址或者使用protected-mode no关闭保护模式(确保防火墙等保护措施到位的情况下);

  • port <sentinel-port>

哨兵使用的端口;

  • daemonize no

默认哨兵不作为守护程序运行,如果设置yes,就会写入一个pidfile指定的pid文件;

  • pidfile /var/run/redis-sentinel.pid

指定pid文件(daemonize设置yes时);

  • logfile ""

指定日志文件名,空字符串时强制哨兵使用标准输出(当使用标准输出并使用守护模式时日志会重定向到/dev/null);

  • sentinel announce-ip <ip>
  • sentinel announce-port <port>

以上两项通常用在NAT环境中明确指定哨兵的ip和端口,当提供明确的announce-ip时,sentinel会在HELLO消息里发布出来,而不是像通常那样自动检测本地ip,当提供明确的非零announce-port时,sentinel也会发布出来(以上两项不需要同时指定,如果只指定ip,则会发布指定的ip和由port项配置的端口,如果只指定port,则会发布指定的port和自动检测的ip);

  • dir <working-directory>

定义工作目录;

  • sentinel monitor <master-name> <ip> <redis-port> <quorum>

告诉哨兵监控这个master(一个哨兵可以监控多个master),并且只有<quorum>个哨兵同意的情况下才将该master标记为客观离线(无论<quorum>为多少,进行故障转移还是需要大多数哨兵的同意);副本是自动被发现的,不需要自己配置,哨兵会自己重写这个配置文件来添加副本(副本被提升为master时配置文件也会被重写);<master-name>不能有特殊字符,可用大小写字母、数字、".-_"三个字符命名;

  • sentinel auth-pass <master-name> <password>

设置master和slave的密码(所以master和slave要使用一样的密码),也可以使用需要认证和不需要认证的master、slave混用(AUTH命令在无认证的redis中无效);

  • sentinel auth-user <master-name> <username>

设置使用指定用户名连接服务;(对redis6或更高版本设置ACL时有效)(服务端最小ACL设置应为:user sentinel-user >somepassword +client +subscribe +publish +ping +info +multi +slaveof +config +client +exec on)

  • sentinel down-after-milliseconds <master-name> <milliseconds>

设置master(或任何连接着的slave、sentinel)主观下线超时(毫秒值,默认30s,即30000);

  • user <username> ... acl rules ...

设置哨兵用户ACL规则;(从redis6.2开始哨兵支持ACL功能)

  • acllog-max-len 128

设置ACL日志最大条目数;(ACL日志用于记录ACL相关命令失败和认证事件,日志存在内存中,可用ACL LOG RESET命令回收内存)

  • aclfile /etc/redis/sentinel-users.acl

指定外部ACL规则文件;使用acl配置和指定外部acl文件不能同时使用,否则无法启动,外部文件格式跟redis.conf里配置acl一样;

  • requirepass <password>

指定哨兵密码;(哨兵将使用该密码验证其他所有哨兵,所以所有哨兵需要相同的密码)(从redis6.2开始,该项只是ACL一个兼容设置,相当于给默认用户设置了密码,使用AUTH <password>和AUTH default <password>都可以;建议新配置文件对入连接(ACL)和出连接(sentinel-user和sentinel-pass)设置不同密码;requirepass跟acl配置或者ACL LOAD命令不兼容,将导致requirepass被忽略)

  • sentinel sentinel-user <username>

设置特定用户名进行身份验证;

  • sentinel sentinel-pass <password>

设置哨兵与其他哨兵的认证密码;(如果没有配置sentinel-user,将使用“default”用户和sentinel-pass命令进行验证)

  • sentinel parallel-syncs <master-name> <numreplicas>

在故障转移时,重新配置多少个副本指向新的master;如果slave提供查询服务需要将该值设置低一些,避免所有的副本同时与master同步导致无法访问;

  • sentinel failover-timeout <master-name> <milliseconds>

指定故障转移超时时间(毫秒,默认3分钟,即180000);该设置会用于多个地方:当给定的哨兵重新进行故障转移时并且之前的故障转移是同一个master,需要的时间是failover-timeout的两倍。当让一个依据哨兵当前配置的从错误master同步的副本去强制同步正确的master的时间,正好就是这个failover-timeout的时间。当一个故障转移正在进行但未产生任何配置改变时,取消该故障转移所需的时间。当故障转移正在进行时,等待所有的副本被重新分配给新的master所用的最大时间,即使超过该时间副本最终也会被哨兵重新分配,只不过不是按照之前确定的并行同步进行的。

  • sentinel notification-script <master-name> <script-path>

用于配置故障转移后,通知管理员的script脚本;对于在WARNING级别中生成的任何哨兵事件(例如-sdown、-odown等)调用通知脚本;脚本应该通过邮件、SMS或者其他消息系统将所监控的redis服务错误通知给管理员;(脚本需要两个参数,第一个是事件类型,第二个是事件描述;如果提供了该项,脚本必须存在并可执行,以便哨兵能够正常启动)

脚本错误处理:如果脚本返回“1”,稍后重试执行(当前最多执行10次);如果脚本返回“2”(或更高值),则不会重试执行;如果脚本因收到信号终止,则跟返回1一样;脚本最大执行时间为60秒,如果超时,脚本会以SIGKILL终止并重试执行;

  • sentinel client-reconfig-script <master-name> <script-path>

用于配置故障转移后,重新配置客户端的script脚本;当故障转移导致master变动时,可以调用一个执行特殊任务的脚本通知客户端配置变动和master地址改变;(传递给脚本的参数是:<master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>,<state>参数总是“failover”,<role>参数是“leader”和“observer”中的一个,后面四个ip和port参数用于说明旧的master和新的master地址)(脚本应该能够被多次调用)

脚本错误处理同上;

  • sentinel deny-scripts-reconfig yes

默认情况下SENTINEL SET将不能在运行时改变通知管理员的脚本和配置客户端的脚本;(这避免了一个安全问题:客户端可以设置任意脚本并在故障转移时执行它)

  • SENTINEL rename-command mymaster CONFIG GUESSME

有时候为了防止客户端在外部使用管理员控制台使用某些敏感命令(如“CONFIG”、“SLAVEOF”),redis服务器会给这些命令重命名,但是哨兵又必须要用这些命令。由于这个原因提供该命令用来告诉哨兵某个master的命令被重命名了;(注意命令不区分大小写,CONFIG GUESSME和config guessme是相同的)

运行时也可以使用SENTINEL SET来执行此设置;

为了还原命令名字(撤销重命名),设置为原本的命令名字即可;(就像:SENTINEL rename-command mymaster CONFIG CONFIG)

  • SENTINEL resolve-hostnames no

设置解析主机名;(通常哨兵只需要一个ip地址,使用SENTINEL MONITOR命令和replica-announce-ip参数指定ip,启用解析主机名时必须DNS配置正确并且延时不高)

  • SENTINEL announce-hostnames no

启用解析主机名时,设置哨兵发布消息时也保留主机名;

  • SENTINEL master-reboot-down-after-period mymaster 0

设置为0时,当哨兵从master收到一个-LOADING响应时不会进行故障转移;(redis7.0之前唯一可支持的行为)否则,在master重启后,故障转移前,哨兵会把该时间(单位ms)作为将要接受-LOADING响应的时间;

测试实验:

redis版本5.0.4;虚拟机地址192.168.1.31;

先搭建一主二从的主从模式:主(6379)、从(6380和6381);

(主redis也需要配置masterauth,用于被切换为slave时使用)

准备3个哨兵配置文件:

设置端口:port 26379 (其余两个哨兵26380和26381)

设置监听的master:sentinel monitor mymaster 192.168.1.31 6379 2

设置master的密码:sentinel auth-pass mymaster 654321

修改超时时间利于测试:sentinel down-after-milliseconds mymaster 5000

(哨兵26379超时为默认30000)

其他配置使用默认的;

先正常启动主从,再启动哨兵;

启动26379哨兵:

 启动26380哨兵:(26379也会多一条日志)

 启动26381哨兵:(其他两个哨兵也会多一条日志)

启动完后,主6379的info:

 哨兵26379的info:

 关掉主6379,哨兵26379、26380、26381的日志分别为:(26381成为leader并故障转移到6380,并发送重写配置通知)

 从6380、6381日志分别为:(都跟6379断开,6381重新从6380同步)

 哨兵26379的info变为:

 新master6380的info:(自己变为主,只有6381一个从)

 重启6379,哨兵26379、26380、26381日志:

 同时新主6380收到了6379的同步请求:

 主6380的info也发生了改变:(6379变为了从)

 关掉哨兵26381和主6380,哨兵26397、26380日志:(26379超时为30s)

 6379被选为新master:

测试通知脚本:

26379哨兵配置文件添加:sentinel notification-script mymaster /home/centos/Documents/redis/test.sh

脚本文件test.sh(因为哨兵工作目录是/tmp,所以这里用了绝对路径)

#!/bin/bash
x="/home/centos/Documents/redis/notifylog.txt"
echo "test" >> $x
echo "参数个数=$#" >> $x
echo "参数1=$1" >> $x
echo "参数2=$2" >> $x
echo -e "...\n" >> $x

 启动6379哨兵后,当有warning级别的日志时,会向调用test.sh脚本,将参数打印到notify.txt文件里(启停master等,脚本可以在哨兵运行时动态改动)

 

哨兵的订阅发布消息:

哨兵是一个特殊服务,不能publish,但可以使用subscribe或psubscribe订阅通道的消息,哨兵会将一些关键事件信息发布到对应通道,用户可以订阅这些通道获得有用信息;

哨兵发布的订阅消息跟哨兵日志里的基本是一致的,比如重启一个从服务器,日志和发布消息如下:

日志格式就是由“通道+消息内容”组成的,通道名跟事件名相同;

以下为可订阅通道列表,前面为通道后面为消息内容:(官网:High availability with Redis Sentinel | Redis,官网上的有几个通道前面丢了+)

<instance details>的格式:<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

@后面为master信息(可选,只有当@前面不是master时才指定)

  • +reset-master <instance details> -- 主服务器被重置;
  • +slave <instance details> -- 一个新的从服务器被检测到并添加关联;
  • +failover-state-reconf-slaves <instance details> -- 故障转移状态切换到 reconf-slaves 状态;
  • +failover-detected <instance details> -- 检测到另一个哨兵或者其他外部实例启动了故障转移(一个从服务器转变为主服务器);
  • +slave-reconf-sent <instance details> -- leader哨兵向这个实例发送了REPLICAOF命令,以便为副本重新配置主服务器;
  • +slave-reconf-inprog <instance details> -- 实例正在将自己设置为新的master的从服务器,但同步仍未完成;
  • +slave-reconf-done <instance details> -- 从服务器与新的master同步完成;
  • -dup-sentinel <instance details> -- 主服务器的一个或多个哨兵由于重复出现而被移除(哨兵重启的时候会发生这种情况);
  • +sentinel <instance details> -- 监控master的新哨兵被检测到并添加关联;
  • +sdown <instance details> -- 指定的实例处于主观下线状态;
  • -sdown <instance details> -- 指定的实例已经不再处于主观下线状态;
  • +odown <instance details> -- 指定的实例处于客观下线状态;
  • -odown <instance details> -- 指定的实例已经不再处于客观下线状态;
  • +new-epoch <instance details> -- 当前纪元已被更新;
  • +try-failover <instance details> -- 新的故障转移正在进行中,等待被大多数选中;
  • +elected-leader <instance details> -- 赢得指定纪元的选举,可以进行故障转移;
  • +failover-state-select-slave <instance details> -- 新的故障转移状态为select-slave,正在试图找一个合适的从服务器提升为master;
  • no-good-slave <instance details> -- 哨兵没有找到合适提升为master的从服务器,哨兵将在一段时间后再次尝试,也可能状态机会终止故障转移;
  • selected-slave <instance details> -- 哨兵找到了合适提升为master的从服务器;
  • failover-state-send-slaveof-noone <instance details> -- 哨兵正在尝试将从服务器配置为master,正在等待切换完成;
  • failover-end-for-timeout <instance details> -- 故障转移因超时而终止,但副本最终将被配置为同步新的master;
  • failover-end <instance details> -- 故障转移成功完成,所有副本都开始同步新master了;
  • switch-master <master name> <oldip> <oldport> <newip> <newport> -- 配置变动,master的地址切换为新的地址;(大多数用户比较关心该项)
  • +tilt -- 进入tilt模式;
  • -tilt -- 离开tilt模式;

例子,主服务宕机的订阅消息:

可以看到哨兵里的日志并没有打印全部的订阅消息,比如那个-role-change通道的消息;

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐