一、redis哨兵简介
主要功能
监控:Sentinel不断的检查master和slave是否正常的运行。
通知:如果发现某个redis节点运行出现问题,可以通过API通知系统管理员和其他的应用程序。
自动故障转移:能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
配置提供者:哨兵作为Redis客户端发现的权威来源:客户端连接到哨兵请求当前可靠的master的地址。如果发生故障,哨兵将报告新地址。
工作机制
* 每个sentinel以每秒钟一次的频率向它所知的master,slave以及其他sentinel实例发送一个 PING 命令
* 如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被sentinel标记为主观下线。
* 如果一个master被标记为主观下线,则正在监视这个master的所有sentinel要以每秒一次的频率确认master的确进入了主观下线状态
* 当有足够数量的sentinel(大于等于配置文件指定的值)在指定的时间范围内确认master的确进入了主观下线状态, 则master会被标记为客观下线
* 在一般情况下, 每个sentinel会以每 10 秒一次的频率向它已知的所有master,slave发送 INFO 命令
* 当master被sentinel标记为客观下线时,sentinel向下线的master的所有slave发送 INFO 命令的频率会从 10 秒一次改为 1 秒一次
* 若没有足够数量的sentinel同意master已经下线,master的客观下线状态就会被移除;
若master重新向sentinel的 PING 命令返回有效回复,master的主观下线状态就会被移除
特点
* sentinel模式是建立在主从模式的基础上,如果只有一个Redis节点,sentinel就没有任何意义
* 当master挂了以后,sentinel会在slave中选择一个做为master,并修改它们的配置文件,其他slave的配置文件也会被修改,比如slaveof属性会指向新的master
* 当master重新启动后,它将不再是master而是做为slave接收新的master的同步数据
* sentinel因为也是一个进程有挂掉的可能,所以sentinel也会启动多个形成一个sentinel集群
* 多sentinel配置的时候,sentinel之间也会自动监控
* 当主从模式配置密码时,sentinel也会同步将配置信息修改到配置文件中,不需要担心
* 一个sentinel或sentinel集群可以管理多个主从Redis,多个sentinel也可以监控同一个redis
* sentinel最好不要和Redis部署在同一台机器,不然Redis的服务器挂了以后,sentinel也挂了
监控
Sentinel会不断检查Master和Slave是否正常
如果Sentinel挂了,就无法监控,所以需要多个哨兵,组成Sentinel网络,一个健康的Sentinel至少有3个Sentinel应用。 彼此在独立的物理机器或虚拟机。
监控同一个Master的Sentinel会自动连接,组成一个分布式的Sentinel网络,互相通信并交换彼此关于被监控服务器的信息
当一个Sentinel认为被监控的服务器已经下线时,它会向网络中的其它Sentinel进行确认,判断该服务器是否真的已经下线
如果下线的服务器为主服务器,那么Sentinel网络将对下线主服务器进行自动故障转移,通过将下线主服务器的某个从服务器提升为新的主服务器,并让其从服务器转移到新的主服务器下,以此来让系统重新回到正常状态
下线的旧主服务器重新上线,Sentinel会让它成为从,挂到新的主服务器下
部署哨兵之前需要了解的基本事情
一个健壮的部署至少需要三个哨兵实例。
三个哨兵实例应该放置在客户使用独立方式确认故障的计算机或虚拟机中。例如不同的物理机或不同可用区域的虚拟机。
sentinel + Redis实例不保证在故障期间保留确认的写入,因为Redis使用异步复制。然而有方式部署哨兵使丢失数据限制在特定时刻,虽然有更安全的方式部署它。
你的客户端要支持哨兵,流行的客户端都支持哨兵,但不是全部。
没有HA设置是安全的,如果你不经常的在开发环境测试,在生产环境他们会更好。你可能会有一个明显的错误配置只是当太晚的时候。
Sentinel,Docker,或者其他形式的网络地址交换或端口映射需要加倍小心:Docker执行端口重新映射,破坏Sentinel自动发现其他的哨兵进程和master的slave列表。稍后在这个文档里检查关于Sentinel和Docker的部分,了解更多信息。
Sentinel的“仲裁会”
主从故障转移时,需要的sentinel认可的票数达到设置的值才可以。
不过,当failover主备切换真正被触发后,failover(故障转移)并不会马上进行,还需要sentinel中的大多数sentinel授权后才可以进行failover。
当sentinel认可不可用的票数达到时(ODOWN),failover被触发。failover一旦被触发,尝试去进行failover的sentinel会去获得“大多数”sentinel的授权(如果票数比大多数还要大的时候,则询问更多的sentinel)
这个区别看起来很微妙,但是很容易理解和使用。例如,集群中有5个sentinel,票数被设置为2,当2个sentinel认为一个master已经不可用了以后,将会触发failover,但是,进行failover的那个sentinel必须先获得至少3个sentinel的授权才可以实行failover。
如果票数被设置为5,要达到ODOWN状态,必须所有5个sentinel都主观认为master为不可用,要进行failover,那么得获得所有5个sentinel的授权。
Sentinel之间和Slaves之间的自动发现机制
然sentinel集群中各个sentinel都互相连接彼此来检查对方的可用性以及互相发送消息。但是你不用在任何一个sentinel配置任何其它的sentinel的节点。因为sentinel利用了master的发布/订阅机制去自动发现其它也监控了统一master的sentinel节点。
通过向名为__sentinel__:hello的管道中发送消息来实现。
同样,你也不需要在sentinel中配置某个master的所有slave的地址,sentinel会通过询问master来得到这些slave的地址的。
每个sentinel通过向每个master和slave的发布/订阅频道__sentinel__:hello每秒发送一次消息,来宣布它的存在。
每个sentinel也订阅了每个master和slave的频道__sentinel__:hello的内容,来发现未知的sentinel,当检测到了新的sentinel,则将其加入到自身维护的master监控列表中。
每个sentinel发送的消息中也包含了其当前维护的最新的master配置。如果某个sentinel发现
自己的配置版本低于接收到的配置版本,则会用新的配置更新自己的master配置。
在为一个master添加一个新的sentinel前,sentinel总是检查是否已经有sentinel与新的sentinel的进程号或者是地址是一样的。如果是那样,这个sentinel将会被删除,而把新的sentinel添加上去。
Slave选举与优先级
在redis配置文件redis.conf中 slave-priority 100
配置表示slave优先级
适用Sentinel模块(unstable,M-S集群管理和监控),需要额外的配置文件支持。slave的权重值,默认100.当master失效后,Sentinel将会从slave列表中找到权重值最低(>0)的slave,并提升为master。如果权重值为0,表示此slave为"观察者",不参与master选举
当一个sentinel准备好了要进行failover,并且收到了其他sentinel的授权,那么就需要选举出一个合适的slave来做为新的master。
slave的选举主要会评估slave的以下几个方面:
与master断开连接的次数
Slave的优先级
数据复制的下标(用来评估slave当前拥有多少master的数据)
进程ID
如果一个slave与master失去联系超过10次,并且每次都超过了配置的最大失联时间(down-after-milliseconds option),并且,如果sentinel在进行failover时发现slave失联,那么这个slave就会被sentinel认为不适合用来做新master的。
更严格的定义是,如果一个slave持续断开连接的时间超过
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state、
就会被认为失去选举资格。符合上述条件的slave才会被列入master候选人列表,并根据以下顺序来进行排序:
sentinel首先会根据slaves的优先级来进行排序,优先级越小排名越靠前(?)。
如果优先级相同,则查看复制的下标,哪个从master接收的复制数据多,哪个就靠前。
如果优先级和下标都相同,就选择进程ID较小的那个。
一个redis无论是master还是slave,都必须在配置中指定一个slave优先级。要注意到master也是有可能通过failover变成slave的。
如果一个redis的slave优先级配置为0,那么它将永远不会被选为master。但是它依然会从master哪里复制数据。
二、redis主从搭建
1、环境介绍
redis 一主二从
10.0.0.107 主
10.0.0.106 从
10.0.0.105 从
2、10.0.0.107 redis主服务器配置文件
vim /usr/local/redis/conf/redis.conf
#监听地址,0.0.0.0代表监控所有网卡
bind 0.0.0.0
#监听端口更改,6379为默认
port 6379
#是否后台启动,Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no )
daemonize yes
#pid存放目录 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定,这里改为/data/redis/redis.pid
pidfile "/data/redis/redis.pid"
#日志存放目录 日志记录方式,默认为标准输出stdout,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null
logfile "/data/redis/redis.log"
#工作目录 指定本地数据库存放目录
dir /data/redis/
#当这个redis为主时需要的密码
requirepass 123456
#当这个redis为从时连接主使用的密码
masterauth 123456
3、10.0.0.106 、10.0.0.105 从服务器配置文件
vim /usr/local/redis/conf/redis.conf
#监听地址,0.0.0.0代表监控所有网卡
bind 0.0.0.0
#监听端口更改,6379为默认
port 6379
#是否后台启动,Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no )
daemonize yes
#pid存放目录 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定,这里改为/data/redis/redis.pid
pidfile "/data/redis/redis.pid"
#日志存放目录 日志记录方式,默认为标准输出stdout,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null
logfile "/data/redis/redis.log"
#工作目录 指定本地数据库存放目录
dir /data/redis/
#当这个redis为主时需要的密码
requirepass 123456
#当这个redis为从时连接主使用的密码
masterauth 123456
#下面部分和主节点不同
#绑定master的ip和port
slaveof 10.0.0.107 6379
# 从节点只读
slave-read-only yes
#从节点在处于快照同步期间是否对外提供服务
slave-serve-stale-data yes
4、启动redis主从服务,三台机器都启动
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
5、主服务器上查看主从信息
[root@localhost ~]# redis-cli
#配置了密码会后需要先auth password进行验证才能继续操作
127.0.0.1:6379> info Replication
NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
#主服务器上查看信息,可以看到有两个从服务器
127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.106,port=6379,state=online,offset=98,lag=1
slave1:ip=10.0.0.105,port=6379,state=online,offset=98,lag=1
master_replid:be52de996337d0fb8d28f2d0093c6f26631dabfb
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:98
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:98
#设置一个key
127.0.0.1:6379> set key1 value1
OK
6、从服务器上查看主从信息
[root@localhost ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
#从服务器上可以看到有主服务器的信息
127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:10.0.0.107
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:70
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:be52de996337d0fb8d28f2d0093c6f26631dabfb
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
#读取上面设置的key
127.0.0.1:6379> get key1
"value1"
三、redis哨兵搭建
1、sentinel.conf 配置文件
在三台机器上都部署和启动redis哨兵 vim /usr/local/redis/conf/sentinel.conf
daemonize yes
logfile "/data/redis/sentinel.log"
#sentinel工作目录
dir "/data/redis/sentinel"
#判断master失效至少需要2个sentinel同意,建议设置为n/2+1,n为sentinel个数
sentinel monitor mymaster 10.0.0.107 6379 2
#设置master和slaves验证密码,如果master配置了密码,那么sentinel也需要配置密码
sentinel auth-pass mymaster 123456
#判断master主观下线时间,默认30s
sentinel down-after-milliseconds mymaster 30000
#若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel failover-timeout mymaster 18000
#关闭保护模式
protected-mode no
启动redis哨兵服务
/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf
如果出现连接不上的报错
5586:S 20 Feb 12:13:51.068 * Connecting to MASTER 192.168.184.133:6379
5586:S 20 Feb 12:13:51.068 * MASTER <-> SLAVE sync started
5586:S 20 Feb 12:13:51.069 # Error condition on socket for SYNC: Connection refused
需要添加protected-mode no 配置,保护模式如果开启并且未配置密码时,只接受回环地址的ipv4和ipv6地址链接,拒绝外部链接。而且正常应该配置多个哨兵,避免一个哨兵出现独裁情况,如果配置多个哨兵那如果开启也会拒绝其他sentinel的连接,导致哨兵配置无法生效。
2、查看sentinel.log日志
在10.0.0.107机器上查看日志,可以看到有检测到一个redis主服务和两个redis slave从服务,以及另外两个redis哨兵
[root@localhost ~]# tailf /data/redis/sentinel.log
6115:X 10 Oct 14:51:04.164 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6115:X 10 Oct 14:51:04.164 # Redis version=4.0.9, bits=64, commit=00000000, modified=0, pid=6115, just started
6115:X 10 Oct 14:51:04.164 # Configuration loaded
6116:X 10 Oct 14:51:04.238 * Running mode=sentinel, port=26379.
6116:X 10 Oct 14:51:04.239 # Sentinel ID is 5649f02b9e8567ba609090548de09b656cde76f9
6116:X 10 Oct 14:51:04.239 # +monitor master mymaster 10.0.0.107 6379 quorum 2
6116:X 10 Oct 14:51:04.240 * +slave slave 10.0.0.106:6379 10.0.0.106 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 14:51:04.241 * +slave slave 10.0.0.105:6379 10.0.0.105 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 14:51:10.068 * +sentinel sentinel 74c7ee8e941c947adb168a13def63a00ac97060d 10.0.0.106 26379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 14:51:13.111 * +sentinel sentinel fa5b3a5d68cbddfce47ba7384596c671c4a7f09f 10.0.0.105 26379 @ mymaster 10.0.0.107 6379
事件说明
· +reset-master :主服务器已被重置。
· +slave :一个新的从服务器已经被 Sentinel 识别并关联。
· +failover-state-reconf-slaves :故障转移状态切换到了 reconf-slaves 状态。
· +failover-detected :另一个 Sentinel 开始了一次故障转移操作,或者一个从服务器转换成了主服务器。
· +slave-reconf-sent :领头(leader)的 Sentinel 向实例发送了 [SLAVEOF](/commands/slaveof.html) 命令,为实例设置新的主服务器。
· +slave-reconf-inprog :实例正在将自己设置为指定主服务器的从服务器,但相应的同步过程仍未完成。
· +slave-reconf-done :从服务器已经成功完成对新主服务器的同步。
· -dup-sentinel :对给定主服务器进行监视的一个或多个 Sentinel 已经因为重复出现而被移除 —— 当 Sentinel 实例重启的时候,就会出现这种情况。
· +sentinel :一个监视给定主服务器的新 Sentinel 已经被识别并添加。
· +sdown :给定的实例现在处于主观下线状态。
· -sdown :给定的实例已经不再处于主观下线状态。
· +odown :给定的实例现在处于客观下线状态。
· -odown :给定的实例已经不再处于客观下线状态。
· +new-epoch :当前的纪元(epoch)已经被更新。
· +try-failover :一个新的故障迁移操作正在执行中,等待被大多数 Sentinel 选中(waiting to be elected by the majority)。
· +elected-leader :赢得指定纪元的选举,可以进行故障迁移操作了。
· +failover-state-select-slave :故障转移操作现在处于 select-slave 状态 —— Sentinel 正在寻找可以升级为主服务器的从服务器。
· no-good-slave :Sentinel 操作未能找到适合进行升级的从服务器。Sentinel 会在一段时间之后再次尝试寻找合适的从服务器来进行升级,又或者直接放弃执行故障转移操作。
· selected-slave :Sentinel 顺利找到适合进行升级的从服务器。
· failover-state-send-slaveof-noone :Sentinel 正在将指定的从服务器升级为主服务器,等待升级功能完成。
· failover-end-for-timeout :故障转移因为超时而中止,不过最终所有从服务器都会开始复制新的主服务器(slaves will eventually be configured to replicate with the new master anyway)。
· failover-end :故障转移操作顺利完成。所有从服务器都开始复制新的主服务器了。
· +switch-master :配置变更,主服务器的 IP 和地址已经改变。 这是绝大多数外部用户都关心的信息。
· +tilt :进入 tilt 模式。
· -tilt :退出 tilt 模式。
3、查看哨兵信息
登陆任意一台redis哨兵,使用info Sentinel查看哨兵信息,这里可以看到目前这个redis主服务器有三个哨兵,redis主服务器为107这台机器,有两个从服务器。
[root@localhost ~]# redis-cli -h 127.0.0.1 -p 26379
127.0.0.1:26379> info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.107:6379,slaves=2,sentinels=3
4、模拟redis主服务器宕机
将10.0.0.107的redis主服务关闭
[root@localhost ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> shutdown
not connected>
查看 sentinel.log 日志,可以看到10.0.0.107失效了,master从10.0.0.107转移到10.0.0.105上了
6116:X 10 Oct 15:07:36.440 # +sdown master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.507 # +odown master mymaster 10.0.0.107 6379 #quorum 2/2
6116:X 10 Oct 15:07:36.507 # +new-epoch 1
6116:X 10 Oct 15:07:36.507 # +try-failover master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.512 # +vote-for-leader 5649f02b9e8567ba609090548de09b656cde76f9 1
6116:X 10 Oct 15:07:36.518 # fa5b3a5d68cbddfce47ba7384596c671c4a7f09f voted for 5649f02b9e8567ba609090548de09b656cde76f9 1
6116:X 10 Oct 15:07:36.519 # 74c7ee8e941c947adb168a13def63a00ac97060d voted for 5649f02b9e8567ba609090548de09b656cde76f9 1
6116:X 10 Oct 15:07:36.565 # +elected-leader master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.565 # +failover-state-select-slave master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.632 # +selected-slave slave 10.0.0.105:6379 10.0.0.105 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.632 * +failover-state-send-slaveof-noone slave 10.0.0.105:6379 10.0.0.105 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:36.704 * +failover-state-wait-promotion slave 10.0.0.105:6379 10.0.0.105 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:37.362 # +promoted-slave slave 10.0.0.105:6379 10.0.0.105 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:37.362 # +failover-state-reconf-slaves master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:37.411 * +slave-reconf-sent slave 10.0.0.106:6379 10.0.0.106 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:37.665 # -odown master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:38.399 * +slave-reconf-inprog slave 10.0.0.106:6379 10.0.0.106 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:38.399 * +slave-reconf-done slave 10.0.0.106:6379 10.0.0.106 6379 @ mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:38.457 # +failover-end master mymaster 10.0.0.107 6379
6116:X 10 Oct 15:07:38.458 # +switch-master mymaster 10.0.0.107 6379 10.0.0.105 6379
6116:X 10 Oct 15:07:38.458 * +slave slave 10.0.0.106:6379 10.0.0.106 6379 @ mymaster 10.0.0.105 6379
6116:X 10 Oct 15:07:38.458 * +slave slave 10.0.0.107:6379 10.0.0.107 6379 @ mymaster 10.0.0.105 6379
6116:X 10 Oct 15:08:08.464 # +sdown slave 10.0.0.107:6379 10.0.0.107 6379 @ mymaster 10.0.0.105 6379
登陆10.0.0.105的redis,查看当前主从信息,可以看到这台机器变为主服务器了,切换成功
[root@localhost ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.106,port=6379,state=online,offset=278079,lag=0
master_replid:5d453e39096c8fe7436557fb6da3f70c3635a38f
master_replid2:be52de996337d0fb8d28f2d0093c6f26631dabfb
master_repl_offset:278079
second_repl_offset:191460
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:278079
5、重新启动redis服务
然后再启动10.0.0.107的redis服务
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
查看sentinel.log 日志,-sdown表示给定的实例已经不再处于主观下线状态,即10.0.0.107重新上线了
6154:X 10 Oct 15:20:43.920 # -sdown slave 10.0.0.107:6379 10.0.0.107 6379 @ mymaster 10.0.0.105 6379
6154:X 10 Oct 15:20:53.837 * +convert-to-slave slave 10.0.0.107:6379 10.0.0.107 6379 @ mymaster 10.0.0.105 6379
在10.0.0.107上登陆redis,然后查看当前主从信息,可以看到107这台机器目前是从服务器,并没有恢复关闭前的主服务器状态。下线的旧主服务器重新上线,Sentinel会让它成为从,挂到新的主服务器下
127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:10.0.0.105
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:390410
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:5d453e39096c8fe7436557fb6da3f70c3635a38f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:390410
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:349324
repl_backlog_histlen:41087