一、Redis哨兵模式搭建
1、准备好三台机器,使用diap用户完成搭建
2、安装Redis
-在资源库中下载redis-7.0.8.tar.gz,分别上传到三台服务器中软件安装的目录,我这里安装到/u01下
-安装依赖。yum -y install gcc-c++(root用户执行),三台服务器都要执行
3、修改Redis配置文件
- 将/redis-7.0.8/redis.conf复制一份到/usr/local/redis/etc中
mkdir /usr/local/redis
Mkdir /usr/local/redis/etc
cp /u01/redis-7.0.8/redis.conf /usr/local/redis/etc
vi /usr/local/redis/etc/redis.conf
- 修改以下内容
daemonize yes #redis后台启动
requirepass !QAZ3edc #设置redis密码
bind 127.0.0.1 注释掉这行
pidfile /usr/local/redis/run/redis_6379.pid
logfile “/usr/local/redis/logs/redis.log”
dir /usr/local/redis/dbcache
masterauth !QAZ3edc #连接主机的密码
#以上内容三台机器都是一样配置,下面的内容在两台从节点上配置
slaveof 10.38.17.82 6379 #是10.38.17.82的从节点
- 保存退出
- 创建配置文件中修改的pid、log、dbcache文件,三台机器一样执行
mkdir /usr/local/redis/run
touch /usr/local/redis/run/redis_6379.pid
mkdir /usr/local/redis/logs
touch /usr/local/redis/logs/redis.log
mkdir /usr/local/redis/dbcache
4、启动Redis,看一主二从是否生效
进入/u01/redis-7.0.8/src,输入以下命令
./redis-server /usr/local/redis/etc/redis.conf #三台机器同时启动redis-server
./redis-cli -p 6379 #启动主节点的客户端redis-cli
127.0.0.1:6379>auth !QAZ3edc # 验证密码
OK
127.0.0.1:6379>info replication
role:master
connected_slaves:2
...
#说明一主二从模式搭建完毕
5、部署哨兵模式
将配置文件sentinel.conf复制到指定目录
cp sentinel.conf /usr/local/redis/etc
vi /usr/local/redis/etc/sentinel.conf
修改以下内容,三台机器都要
Daemonize yes
pidfile /usr/local/redis/run/redis-sentinel.pid
logfile "/usr/local/redis/logs/redis-sentinel.log"
dir /usr/local/redis/tmp
sentinel monitor mymaster 10.38.17.82 6379 2 #设置redis主机IP地址,端口,选举次数
sentinel auth-pass mymaster !QAZ3edc #设置redis主机访问密码
sentinel down-after-milliseconds mymaster 8000 #心跳检测8000毫秒,如果主机8秒内没有
创建配置中修改的pid、log、tmp文件(三台机器都要)
touch /usr/local/redis/run/redis-sentinel.pid
touch /usr/local/redis/logs/redis-sentinel.log
mkdir /usr/local/redis/tmp
6、启动哨兵模式
#进入/redis-7.0.8/src目录
./redis-sentinel /usr/local/redis/etc/sentinel.conf #三台机器都一样
#连接主节点的哨兵客户端
./redis-cli -p 26379
127.0.0.1:26379>ping
PONG
127.0.0.1:26379>info sentinel
#Sentinel
Sentinel_masters:1
...
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves:2,sentinels=3
这样哨兵模式就搭建完毕。查询当前的主节点,在哨兵模式客户端输入命令SENTINEL get-master-addr-by-name mymaster mymaster
模拟主节点宕机:用kill命令将主节点的redis-server关闭,连接从节点redis-cli客户端,观察是否从slave变为master(总有一台从节点会自动变为主节点
二、哨兵模式工作原理
2.1、哨兵模式工作原理
哨兵是Redis的一种工作模式,以监控节点状态及执行故障转移 为主要工作,哨兵总是以固定的频率去发现节点、故障检测 ,然后在检测到主节点故障时以安全的方式执行故障转移,确保集群的高可用性。
2.2、节点自动发现
这里的节点指的是其他哨兵节点和主从节点 。
1、自动发现数据节点(主从节点):
一般情况下,哨兵节点每隔10秒(故障转移时每隔1秒)向主从节点发送INFO命令,以此获取主从节点的信息。第一次执行时,哨兵仅知道我们给出的主节点信息,通过对主节点执行INFO命令,就可以获取其从节点列表,如此周期性执行,就可以不断发现新加入的节点
- 如果INFO命令目标是从节点:哨兵从返回信息中获取从节点所属的最新主节点ip和port,如果与历史记录不一致,则执行更新
- 如果INFO命令目标是主节点:哨兵从返回信息中获取主节点的从机列表,如果从节点是新增的,则将其加入监控列表
2、自动发现其他哨兵节点:
Redis提供了一种发布订阅的消息通信模式,即Pub/Sub,哨兵们就是通过一个约定好的通道(channel)发布/订阅hello信息进行通信。
-
每隔2秒,每个哨兵会通过它监控的主节点、从节点向通道发布一条hello信息
-
每个哨兵会通过它所监控的主节点、从节点订阅通道的信息,以此接收其他哨兵发布的信息
-
每个哨兵都会维护其监控的主节点信息,如果它接收到其他哨兵消息后,发现自己维护的信息已经过时,则立即执行更行过程。
-
如果哨兵接受到的信息没有在已有的监控列表中,就意味着发现了一个新的哨兵实例,此时会创建一个新的哨兵实例加入监控列表。在处理新增哨兵实例时,如果它与已存在的哨兵实例runId或者ip、port一致,将只保存最新的实例信息。
3、总结
节点发现的过程就是这样:对于数据节点采用INFO命令询问,从一个主节点得到从节点,再通过从节点检验主节点,实现数据节点发现;对于其他哨兵节点,借助正在被监控的数据节点以类似广播的方式,实现节点的发现。
2.3、故障检测
1、故障检测
故障检测是哨兵执行故障转移的前提,在知晓需要监控的目标(主从节点)后,哨兵通过PING命令实现对主从节点的故障检测。
哨兵以集群方式工作,官方建议至少要有三个节点 (一主二从节点部署哨兵模式),每个节点都以相同的方式对主从节点进行监控与故障检测。由于网络抖动或者网络分区,单个哨兵对节点的故障检测可能无法代表其真实的状态,为了降低误判,哨兵之间还需要对节点的故障状态进行协商 。所以这里需要引入两个概念:
- 主观宕机(SDOWN):是指一个哨兵 实例通过检测发现某个主节点发生故障的一种状态、
- 客观宕机(ODOWN):是指哨兵检测到某个主节点发生故障,通过命令SENTINEL is-master-down-by-addr 与其他哨兵节点协商,并且在指定时间内接收到指定数量的其他哨兵的确认反馈时的一种状态
简单来说,SDOWN是哨兵自己认为节点宕机,而ODOWN是不但哨兵自己认为节点宕机,而且该哨兵与其他节点沟通后,达到一定数量的哨兵都认为节点宕机
这个一定数量可以配置:
sentinel monitor mymaster xx.xx.xx.xx 6379 2
这里的 2:代表只有两个或两个以上的哨兵认为主节点不可用的时候,才会把主节点设置为ODOWN状态,然后进行failovor操作
2、Redis如何实现SDOWN和ODOWN
- 主观宕机SDOWN
Redis以类似心跳检测的PING命令对节点进行健康检查,然后根据节点的回复情况进行状态管理。
SDOWN状态是指在sentinel down-after-milliseconds 时间内未收到节点的PING命令回复,这个是在sentinel.conf中的sentinel down-after-milliseconds mymaster配置,如
sentinel down-after-milliseconds mymaster 8000 ##心跳检测8000毫秒,如果主机8秒内没有相应,就会将主节点设置为SDOWN
SDOWN无法触发故障转移 ,仅仅说明是一个哨兵认为节点发送故障(不可用)了,若要触发故障转移,必须达到ODOWN状态
- 客观宕机DOWN
当Sentinel将一个主节点判断为主观下线之后,为了确认这个主服务器是否真的下线 了,它会向同样监视这一主服务器的其他Sentinel进行询问,看它们是否也认为主服务器已经进入了下线状态。当Sentinel从其他Sentinel那里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器执行故障转移操作 。
ODOWN状态仅应用在主节点上 ,不对从节点及其他哨兵节点应用,但是SDOWN状态对他们都是有效的
2.4、故障转移
1、进入故障转移过程有几个前提:
- 主节点为客观宕机状态
- 当前没有故障转移在执行
- 上次故障转移已经超时
故障转移执行过程中的核心过程主要为Sentinel Leader选举,新主节点选举,配置其他从节点
2、Sentinel Leader选举
当一个主节点被判断为客观下线时,监控这个主节点的所有Sentinel会进行协商,选举一个Leader对下线的主节点执行故障转移操作 。故障检测是多个Sentinel同时执行 的,也就是说可能多个Sentinel在相近的时间内都判定主节点客观宕机了,因此Leader的选举过程在Sentinel集群内可能是同步进行的。所以,Sentinel需要在集群内进行“拉票”,“拉票”的依据就是配置纪元及“拉票”的时间。配置纪元越大,优先级越高;“拉票”请求越早,优先级越高 :
-
当Sentinel判断主节点客观下线后,会把自己的配置纪元加1,未检测到主节点ODOWN或检测慢的,自然落后于当前纪元
-
Sentinel会使用Sentinel is-master-down-by-addr命令向其他所有Sentinel发起投票请求,与故障检测过程中的“询问“不同,这里的runId将被设置为当前Sentinel的runId,epoch为最新的纪元。
-
其他Sentinel接收到“投票”请求后,执行以下过程:
-
- 若请求纪元大于自身配置纪元 ,则更新替换;若监控主节点的配置纪元小于请求纪元,则更新替换,并“投票”给发起请求的Sentinel 。这个过程是抢占式的,同一纪元,先到先得。(Redis命令处理是单线程,无并发冲突)。
- 根据判断结果,回复“投票”请求:回复内容为该Sentinel选举的Leader的runId。
-
Sentinel接收并处理Sentinel is-master-down-by-addr回复:把投票结果(runId)更新到该Sentinel的节点信息中。
投票结束,进行统计结果。该过程是在SENTINEL_FAILOVER_STATE_WAIT_START状态下执行的。Sentinel会遍历当前主节点下所有的Sentinel节点,把它们的投票信息进行统计;然后判断是否有Sentinel胜出。这里胜出的条件是:
- Sentinel必须获取集群内大多数Sentinel的选票,即票数大于50% (防止“脑裂“出现两个leader);
- Sentinel所获票数必须大于等于法定人数 (quorum);(配置文件中设置的)
3、新主节点选举
选举出Sentinel Leader后,Sentinel Leader会从该宕机的主节点的存活的从节点中选出一个新的主节点。首先,按照一下条件剔除从节点:
- 主观宕机(SDOWN)或与处于断线状态的从节点;
- 最近5秒内未回复过Sentinel Leader INFO命令的从节点;
- 从节点的优先级为0的从节点,由配置项replica-priority决定;
- 与主节点断开连接超过10倍down-after-milliseconds的从节点;
然后按照以下规则选择新的节点:
- 选择replica-priority最低的节点。如果存在相同,则继续;
- 选择复制偏移量最大的的从节点。如果存在相同,则继续;
- 选择runId最小的从节点;
选出新的主节点之后,Sentinel Leader会向它发送slaveof NO ONE ,把这个从节点转为主节点(这是在从节点自身来看的角色转换)。
从节点接收slaveof NO ONE命令后,会重置其主节点信息,断开与其主节点、从节点的网络连接,重置其复制ID,并执行持久化重写操作。
4、配置其他从节点
新的主节点已经配置完成,接下来就是要让其他存活的从节点以该节点为主节点,然后向该节点发起主从复制,该过程原理比较简单:遍历原主节点的从节点,向这些从节点发送slaveof 命令
这样故障转移过程就完成。新的主节点也诞生。
5、注意:
Sentinel从不移除从节点,即使很长时间都不可用。这一点是非常有用的,因为当发生网络分区或者故障后,Sentinel需要正确的对恢复节点进行重新配置。经过故障转移,旧主节点将以从节点的角色加入集群 ,Sentinel会对他进行重新配置,让它从新的主节点执行主从复制。即使旧的主节点恢复,仍然是以从节点的身份加入集群,不再是主节点。
脑裂问题:redis的主从模式下脑裂是指因为网络问题,导致redis 主节点跟从节点和Sentinel集群处于不同的网络分区 ,此时因为Sentinel集群无法感知到 主节点的存在,就会将某一个从节点提升为主节点。此时就存在两个不同的主节点 ,就像一个大脑分裂成了两个。