0. 引言

上一章我们讲解了redis的主从搭建,但要实现真正的可靠的主从结构,还需要实现主从切换。也就是当主节点宕机时,从节点能够自动切换为主节点。

这就需要借助哨兵模式来实现,今天我们就来看如何搭建哨兵模式

1. 原理

1.1 哨兵的作用

所谓哨兵就是有一个放哨的,一旦发现主节点不行了,就会告诉从节点顶上。

它的核心作用有三个:

  • 监控节点状态,判断主节点是否挂掉
  • 当主节点挂掉时,进行主从切换,选出新的主节点
  • 将选出新主的消息告诉其他节点以及客户端

所以它的原理其实就围绕这三点展开

1.2 监控节点状态

哨兵会定时发送三个任务:
(1)每10s会向主节点发送info指令,并通过主节点来获取配置的从节点信息,也就是主从节点的网络拓扑图(结构信息)。这样当有新的从节点配置进来时可以感知到
(2)每2s广播当前哨兵对于主节点的判断(是否主观下线)以及当前哨兵节点的信息(让别的哨兵知道“我”还活着)。这里广播是通过redis的发布订阅模式来实现的。
(3)每1s会向主从节点、其他哨兵发送ping命令,也就是心跳检测,检查这些节点是否还活着。

1、从第三个任务我们可以看到,哨兵每1s会发送一个ping命令给监控的主从节点,在规定时间内(is-master-down-after-milliseconds)没有收到有效回复时就会认为这个节点下线了。

但是这里会涉及一个问题,生活中我们一般认为一个人的想法是主观想法,大多数人的想法近似于客观想法。redis中也有这样一个概念,一个哨兵节点认为某个节点挂了,这是主观下线;大多数哨兵节点认为某个节点挂了,这是客观下线。这样的好处也很明显,可以减少误判。

比如说某个哨兵节点的网络刚好有波动,ping节点时没有ping通,结果就认为redis节点挂了,实际上是网络的问题。而大多数哨兵都同时出现网络问题的概念就比较低了,触发机房整体出现网络问题,那这是redis节点也自然挂了。

2、所以当一个哨兵节点认为这个主节点主观下线后,就会发送命令is-master-down-by-addr询问其他哨兵,该节点有没有下线。

3、如果达到指定数量(quorum,默认半数以上)的哨兵节点都认为某个主节点主观下线了, 该哨兵就会认为该主节点客观下线了。

通过这样来监控节点的状态

在这里插入图片描述

1.3 哨兵的的个数

当哨兵判定某个节点为客观下线后,就会向其他哨兵发起投票,选出一个leader哨兵,最后由这个leader哨兵来进行主从切换

所以我们一般要求哨兵节点为2个及以上,且为奇数,也就是至少3个。想想为什么?

因为如果为偶数个的哨兵节点时,就会出现"脑裂"问题,这个在es集群中也比较常见,比如一半的哨兵投了反对票, 一半的投了支持票,请问最终结果如何?

其次因为哨兵需要半数以上投票通过才能通过,当为2节点时。如果宕机了一个节点,就永远只有一个节点,则永远不能超过半数以上了,而为2节点时,即使宕机1个,还有2个节点可以投票,也能满足半数以上。

所以,我们必然需要奇数个哨兵才能真正投票出结果

在这里插入图片描述

1.4 哨兵的投票机制

但奇数个哨兵就万事大吉了吗?如果每个哨兵都投个自己,那不是没法选出一个leader了吗?

redis哨兵的投票算法当然想到了这点。

1、首先,最先发现主节点为客观下线的哨兵,redis将其定义为“候选者”

2、候选者会先投自己一票,可以理解为“我发现的问题,我要自己解决”

3、然后会向其他哨兵发起投票请求(请把票投给我),每个哨兵都有一票,候选者可以把票投给自己,非候选者收到投票请求后,可以选择同意或拒绝,如果收到两个候选者的投票请求,先到先得。

4、候选者会统计自己获取到的票数,直到获取的票数超过半数,且超过所配置的quorum数,这次选举就成功了,会晋升为Leader,并且负责主从切换事宜。

在这里插入图片描述

1.5 哨兵主从切换

当选举出哨兵Leader后,就可以进行主从切换了。

1、从挂掉的主节点下的所有的从节点中选一个状态健康、优先级高且数据完整的从节点。

所谓状态健康就是网络连接正常的,主要是主从节点在down-after-milliseconds 时间内产生过网络通信的即可认为是健康的从节点。

而优先级高则是根据slave-priority配置的值来判定的

数据完整则是当优先级相同,复制的数据下标越多则数据越完整(主从复制时从节点会记录复制的数据下标),如果优先级和数据完整都想同时就会选择节点ID最小的那个

这里大家可能会想:“哨兵是怎么知道主节点下有哪些从节点的,主节点不是都挂掉了吗?”
答:还记得我们上面讲的哨兵的三个定时任务吗?哨兵就是通过第一个定时任务获取的从节点信息,并且记录在册,以供使用。

2、然后通过指令slaveof no one清除这个从节点的SLAVE信息,也就是取消掉其附属的主节点,让其成为主节点。

3、同时将挂掉的主节点的所有从节点信息再挂载到新的主节点上

4、至此,内部的主从转换就完成了,但下一步我们还需要将新主节点的信息广播给客户端。当然这里的广播是通过redis的发布/订阅模式来实现的

5、还没完,旧的主节点哨兵也会持续监听,当它恢复后,哨兵会将其作为从节点挂载到新主节点上。所以这里要注意,主节点宕机后再恢复,并不会自动再切回主节点,而是作为从节点存在。

至此,我们关于哨兵模式的原理就介绍完成了。下面我们来看具体实操。

在这里插入图片描述

2. 哨兵搭建

1、首先准备三个节点,一主双从,并启动。如果不知道如何搭建的,可以参考我之前的文章:

安装redis的四种方式

redis进阶:搭建redis主从架构

2、可以单独启动redis节点作为哨兵节点,也可以配置到原有的数据节点(主从节点)中,这里为了节约服务器资源,我们将哨兵配置到原来的主从节点中

3、哨兵有一个单独的配置文件sentinel.conf,在redis的安装目录下可以看到

在这里插入图片描述

4、修改三个节点的配置文件

vim sentinel.conf 

修改内容:

# 关闭保护模式
protected-mode no
# 哨兵监听端口,默认26379
port 26379
# 后台启动,即开启守护进程
daemonize yes
# 日志路径
logfile "/var/local/redis/logs/sentinel.log"
# 指定数据存放路径,默认/tmp
dir "/tmp"
# 监听的主节点 mymaster为主节点名称,最后的2为quorum值
sentinel monitor mymaster 192.168.244.27 6379 2
# 如果master节点有密钥要补充密码
#sentinel auth-pass mymaster xxx
# 判定服务器down掉的时间周期,默认30000毫秒(30秒)
sentinel down-after-milliseconds mymaster 30000
# 故障节点的最大超时时间为180000(180秒)
sentinel failover-timeout mymaster 180000

5、如果未关闭防火墙,需要开启哨兵监听端口

# 查询端口是否开放
firewall-cmd --query-port=26379/tcp
# 开启端口
firewall-cmd --add-port=26379/tcp --permanent
# 开启后重新加载
firewall-cmd --reload

6、启动哨兵

cd redis安装目录
redis-sentinel sentinel.conf

7、查看日志

tail -f /var/local/redis/logs/sentinel.log

在这里插入图片描述

8、查看哨兵是否启动
(1)通过ps指令查询

ps -ef | grep sentinel 

在这里插入图片描述

(2)通过redis-cli连接哨兵节点,连接成功说明启动成功

在这里插入图片描述

3. 测试

1、关闭主节点
(1)查询进程

ps -ef | grep reids

在这里插入图片描述
(2)kill 主节点

kill -9 1212

2、查看哨兵日志

可以看到已经切换到从节点28服务器了
在这里插入图片描述

3、查看从节点信息,到新主节点上执行

redis-cli info replication

从节点已经更新为主节点了,并且其下现在只有一个从节点

在这里插入图片描述

4、我们再把原主节点启动起来

service redis start
# 我这里已经将启动脚本配置到/etc/init.d文件夹并命名为redis了,所以可以通过service启动,如果没有配置的,使用以下指令启动
redis-server /etc/redis/6379.conf

5、观察哨兵日志,发现原主节点被转换为从节点

在这里插入图片描述

6、再次观察从节点信息

新增了一个从节点,即原来的主节点,与我们上述的原理解析相符

在这里插入图片描述

7、我们在尝试在新节点上更新一个key

在这里插入图片描述

8、从节点查看该key

在这里插入图片描述

在这里插入图片描述

主从切换成功,哨兵搭建完成

4. 配置哨兵开机启动

1、之前我们已经讲解了设置redis开机自启,我们在此基础上操作

2、修改原有redis启动脚本

vim /etc/init.d/redis

脚本内容

REDISPORT=6379
# 配置哨兵端口
REDIS_SENTINEL=26379
EXEC=/var/local/redis/redis-6.2.7/src/redis-server
CLIEXEC=/var/local/redis/redis-6.2.7/src/redis-cli
# 配置哨兵执行脚本
EXEC_SENTINEL=/var/local/redis/redis-6.2.7/src/redis-sentinel

PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"
# 哨兵配置文件路径
SENTINEL_CONF="/var/local/redis/redis-6.2.7/sentinel.conf"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
                # 启动哨兵服务
                echo "Starting Redis-Sentinel server..."
                $EXEC_SENTINEL $SENTINEL_CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT shutdown
                # 关闭哨兵服务
                echo "Stoping sentinel..."                 
                $CLIEXEC -p $REDIS_SENTINEL shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

3、如果之前没配置过,则需要操作以下步骤,如果已经按照过我之前的配置添加过redis开机自启的则无需配置

(1)赋予文本权限

chmod 777 /etc/init.d/redis

(2)添加开机自启

chkconfig redis on

4、重启哨兵服务器,连接哨兵端口测试

redis-cli -p 26379

在这里插入图片描述

连接成功,说明启动成功

总结

至此,我们哨兵模式的搭建就完成了,希望大家可以借此更加深入理解redis原理,下一期,我们继续讲解redis的集群模式,实现真正的redis高可用

Logo

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

更多推荐