redis 哨兵
一,哨兵概述
哨兵(sentinel),用于对主从结构中的每一台服务器进行监控,当主节点出现故障后通过投票机制来挑选新的主节点,并且将所有的从节点连接到新的主节点上。前面的主从是最基础的提升Redis服务器稳定性的一种实现方式,但我们可以看到master节点仍然是一台,若主节点宕机,所有从服务器都不会有新的数据进来,如何让主节点也实现高可用,当主节点宕机的时候自动从从节点中选举一台节点提升为主节点就是哨兵实现的功能。
二,哨兵作用
1.监控:监控主从节点运行情况。
2.通知:当监控节点出现故障,哨兵之间进行通讯。
自动故障转移:当监控到主节点宕机后,断开与宕机主节点连接的所有从节点,然后在从节点中选取一个作为主节点,将其他的从节点连接到这个最新的主节点。最后通知客户端最新的服务器地址。
三,哨兵的工作方式
1.每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个PING命令。
2.如果一个实例(instance)距离最后一次有效回复PING命令的时间超过 own-after-milliseconds 选项所指定的值,则这个实例会被Sentinel标记为主观下线。
3.如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
4.当有足够数量的Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态,则Master会被标记为客观下线。
5.在一般情况下,每个Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
6.当Master被Sentinel标记为客观下线时,Sentinel 向下线的 Master 的所有Slave发送 INFO命令的频率会从10秒一次改为每秒一次。
若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除。 若 Master重新向7.Sentinel 的PING命令返回有效回复,Master的主观下线状态就会被移除。
四,哨兵架构图
五,哨兵部署
5.1哨兵环境
主机名 | ip地址端口 | 角色 |
---|---|---|
sentinel | 10.0.0.88 26380 | 哨兵1 |
sentinel | 10.0.0.88 26381 | 哨兵2 |
sentinel | 10.0.0.88 26382 | 哨兵3 |
5.2哨兵配置
# pid文件路径
pidfile /var/run/redis-sentinel.pid
# 日志文件路径
logfile "/var/log/sentinel.log"
# 定义工作目录
dir /tmp
# 定义Redis主的别名, IP, 端口,这里的2指的是需要至少2个Sentinel认为主Redis挂了才最终会采取下一步行为
# sentinel monitor [集群名称] [集群主节点IP] [断开] []
sentinel monitor mymaster 127.0.0.1 6379 2
# 如果mymaster 30秒内没有响应,则认为其主观失效
sentinel down-after-milliseconds mymaster 30000
# 如果master重新选出来后,其它slave节点能同时并行从新master同步数据的台数有多少个,显然该值越大,所有slave节点完成同步切换的整体速度越快,但如果此时正好有人在访问这些slave,可能造成读取失败,影响面会更广。最保守的设置为1,同一时间,只能有一台干这件事,这样其它slave还能继续服务,但是所有slave全部完成缓存更新同步的进程将变慢。
sentinel parallel-syncs mymaster 1
# 该参数指定一个时间段,在该时间段内没有实现故障转移成功,则会再一次发起故障转移的操作,单位毫秒
sentinel failover-timeout mymaster 180000
# 不允许使用SENTINEL SET设置notification-script和client-reconfig-script。
sentinel deny-scripts-reconfig yes
# 主库账号密码
sentinel auth-pass mymaster 123
sentinel auth-user mymaster default
# 三个哨兵示例配置
[root@sentinel /usr/local/redis/conf]# egrep -v '^#|^$' sentinel_26380.conf
port 26380
daemonize yes
pidfile /var/run/redis-sentinel_26380.pid
logfile "/usr/local/redis/conf/sentinel_26380.log"
dir /tmp
sentinel monitor mymaster 172.16.1.81 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
sentinel auth-pass mymaster 123
sentinel auth-user mymaster default
5.3 启动多实例哨兵
[root@sentinel /usr/local/redis/conf]# ../bin/redis-sentinel sentinel_26380.conf
[root@sentinel /usr/local/redis/conf]# ../bin/redis-sentinel sentinel_26381.conf
[root@sentinel /usr/local/redis/conf]# ../bin/redis-sentinel sentinel_26382.conf
[root@sentinel /usr/local/redis/conf]# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:26380 0.0.0.0:* LISTEN 11591/../bin/redis-
tcp 0 0 0.0.0.0:26381 0.0.0.0:* LISTEN 11600/../bin/redis-
tcp 0 0 0.0.0.0:26383 0.0.0.0:* LISTEN 11608/../bin/redis-
5.4 查看哨兵监控状态
[root@sentinel /usr/local/redis/conf]# ../bin/redis-cli -p 26380
127.0.0.1:26380> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "172.16.1.81"
5) "port"
6) "6379"
7) "runid"
8) "63e1b63288c82c1ff20784626042aeaadd23f2d0"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
5.5测试故障转移
# 停掉主库
[root@redis01 /usr/local/redis/conf]# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 172.16.1.81:6379 0.0.0.0:* LISTEN 14345/../bin/redis-
[root@redis01 /usr/local/redis/conf]# kill -9 14345
# 查看sentinel 82以变成主库
127.0.0.1:26380> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "172.16.1.82"
5) "port"
6) "6379"
7) "runid"
8) "007268419484bb9391e38ccf617fbbfaabc36fa0"
9) "flags"
10) "master"
# 启动主库查看
[root@redis01 /usr/local/redis/conf]# ../bin/redis-server redis.conf
# 已经变成从库了
[root@redis01 /usr/local/redis/conf]# ../bin/redis-cli
127.0.0.1:6379> INFO replication
127.0.0.1:6379> AUTH 123
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:172.16.1.82
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:226331
# 查看哨兵日志
[root@sentinel /usr/local/redis/conf]# tail sentinel_26380.log
11591:X 18 Dec 2020 20:47:33.491 * +slave-reconf-sent slave 172.16.1.83:6379 172.16.1.83 6379 @ mymaster 172.16.1.81 6379
11591:X 18 Dec 2020 20:47:34.460 * +slave-reconf-inprog slave 172.16.1.83:6379 172.16.1.83 6379 @ mymaster 172.16.1.81 6379
11591:X 18 Dec 2020 20:47:34.460 * +slave-reconf-done slave 172.16.1.83:6379 172.16.1.83 6379 @ mymaster 172.16.1.81 6379
# 81 检测down掉
11591:X 18 Dec 2020 20:47:34.560 # -odown master mymaster 172.16.1.81 6379
11591:X 18 Dec 2020 20:47:34.560 # +failover-end master mymaster 172.16.1.81 6379
11591:X 18 Dec 2020 20:47:34.560 # +switch-master mymaster 172.16.1.81 6379 172.16.1.82 6379
# 82被重新选举会主库
11591:X 18 Dec 2020 20:47:34.560 * +slave slave 172.16.1.83:6379 172.16.1.83 6379 @ mymaster 172.16.1.82 6379
11591:X 18 Dec 2020 20:47:34.560 * +slave slave 172.16.1.81:6379 172.16.1.81 6379 @ mymaster 172.16.1.82 6379
11591:X 18 Dec 2020 20:48:04.594 # +sdown slave 172.16.1.81:6379 172.16.1.81 6379 @ mymaster 172.16.1.82 6379
11591:X 18 Dec 2020 20:49:07.859 # -sdown slave 172.16.1.81:6379 172.16.1.81 6379 @ mymaster 172.16.1.82 6379
六,sentinel管理命令
#连接sentinel管理端口
[root@sentinel ~]# redis-cli -p 26380
#检测状态,返回PONG
127.0.0.1:26380> ping
PONG
#列出所有被监视的主服务器
127.0.0.1:26380> SENTINEL masters
#列出所有被监视的从服务器
127.0.0.1:26380> SENTINEL slaves mymaster
#返回给定名字的主服务器的IP地址和端口号
127.0.0.1:26380> SENTINEL get-master-addr-by-name mymaster
1) "172.16.1.51"
2) "6379
#重置所有名字和给定模式
127.0.0.1:26380> SENTINEL reset mymaster
#当主服务器失效时,在不询问其他Sentinel意见的情况下,强制开始一次自动故障迁移。
127.0.0.1:26380> SENTINEL failover mymaster
七,设置权重,指定主库的优先级
#查看81的权重
127.0.0.1:6379> CONFIG GET slave-priority
1) "slave-priority"
2) "100"
#修改81的权重值为0
127.0.0.1:6379> CONFIG set slave-priority 0
OK
127.0.0.1:6379> CONFIG GET slave-priority
1) "slave-priority"
2) "0"
# 权重值越低越不会优先切换为主库
八,哨兵故障转移原理以及检测机制
8.1 三个定时任务
1.每10秒每个sentinel会对master和slave执行info命令,这个任务达到两个目的:
a)发现slave节点
b)确认主从关系
2.每2秒每个sentinel通过master节点的channel交换信息(pub/sub)。master节点上有一个发布订阅的频道(sentinel:hello)。sentinel节点通过__sentinel__:hello频道进行信息交换(对节点的"看法"和自身的信息),达成共识。
3.每1秒每个sentinel对其他sentinel和redis节点执行ping操作(相互监控),这个其实是一个心跳检测,是失败判定的依据。
8.2 主观下线与客观下线
-
主观下线
所谓主观下线(Subjectively Down, 简称 SDOWN)指的是单个Sentinel实例对服务器做出的下线判断,即单个sentinel认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)。如果服务器在down-after-milliseconds给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(SDOWN )。sentinel会以每秒一次的频率向所有与其建立了命令连接的实例(master,从服务,其他sentinel)发ping命令,通过判断ping回复是有效回复,还是无效回复来判断实例时候在线(对该sentinel来说是“主观在线”)。sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度,如果实例在down-after-milliseconds毫秒内,返回的都是无效回复,那么sentinel回认为该实例已(主观)下线,修改其flags状态为SRI_S_DOWN。如果多个sentinel监视一个服务,有可能存在多个sentinel的down-after-milliseconds配置不同,这个在实际生产中要注意。 -
客观下线
客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断,然后开启failover。
客观下线就是说只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(ODOWN)。
只有当master被认定为客观下线时,才会发生故障迁移。
当sentinel监视的某个服务主观下线后,sentinel会询问其它监视该服务的sentinel,看它们是否也认为该服务主观下线,接收到足够数量(这个值可以配置)的sentinel判断为主观下线,既任务该服务客观下线,并对其做故障转移操作。
客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操。