# Redis三主三从集群高可用检查维护文档

# 前言

三主三从是redis cluster最常用的架构,每个从节点复制的都不是本机主库的数据,而是其他节点主库的数据,这样即使某一台主机坏掉了,从节点备份还是在其他机器上,这样就做到了高可用,三主三从架构允许最多坏一台主机。

三台服务器部署时,三主三从我们采用交叉复制架构类型,这样可以做到最多坏一台主机集群还是正常可以用的,如果每台主机的6381节点都是6380节点的备份,那么这台机器坏了,集群就不可用了,因此想要做到高可用,就必须采用交叉复制。如下面架构图所示。

# 系统架构图

三台服务器部署redis集群三主三从(高可用)合理架构图

1747210218149.png

# 三主三从集群的创建

集群创建时,默认是采用的交叉复制方式,将3个主节点放在3台主机,且每个主节点slave都存放在别的主机。(M:开头为主节点;S:开头为从节点);如下图

1747210271790.png

三个主节点分别是:10.2.5.121:6380、10.2.5.122:6380、10.2.5.124:6380 三个从节点分别是:10.2.5.121:6381、10.2.5.122:6381、10.2.5.124:6381

# 三主三从集群的停止与启动

步骤1、停止:先停三个从节点,再停三个主节点

步骤2、删除所有主节点、从节点的dump.rdb文件(OA不需要redis持久化数据)

步骤3、启动:先启动三个主节点,再启动三个从节点

重启完成后,请执行检查命令,检查集群状态,确认没有出现2个主节点在同一台主机。

./redis-cli --cluster check 10.2.5.121:6380 -a Seeyon123456

1747210301279.png

# 集群高可用注意事项

集群高可用因避免出现2个主节点再同一台服务器。 可能出现的情况如下:

1、其中一台主机发生故障,主机上的2个redis节点宕机,集群主从做了切换。

模拟10.2.5.121服务器宕机,此时查询redis集群状态如下

1747210320136.png

可以看出2个主节点:10.2.5.122:6380、10.2.5.122:6381,在同一台服务器上了。此时,再启动121上的2个redis服务,就是变成从节点。

2、手动停过redis服务

1747210330796.png

如果出现2个主节点再同一台服务器,我们需要把关系切换回来,不能让一台机器上同时存在两台主库,每次故障处理后一定要把主从架构修改会原来的样子。

解决策略:将原来的主库(新从库)重新变为主库

已下图为例:10.2.5.122服务器出现了2个主节点。在集群创建时,10.2.5.122:6381原本是从节点,现在变成了主节点,它对应的从节点10.2.5.121:6380原本是主节点,现在变成了从节点,原因就是2者之间做了主从切换

1747210343788.png

解决方法一:在122服务器上停掉主节点M2,等121上的从节点S2切换成主后,在重新启动

1747210355947.png

解决方法二:将10.2.5.121:6380从库切换成主库,只需要连上10.2.5.121:6380,执行CLUSTER FAILOVER即可变为主库

将新从库重新切换为主库

[root@redis-1 ~]# redis-cli -h 10.2.5.121 -p 6380 -a Seeyon123456
10.2.5.121:6380> CLUSTER FAILOVER
OK

1747210376185.png

# 附言

主从数据同步原理:

1、全量同步

当一个redis服务器初次向主服务器发送salveof命令时,redis从服务器会进行一次全量同步。

salveof:将当前服务器转变为指定服务器的从属服务器,就是给主机加一个从机

1、 slave服务器向master发送psync命令,告诉master我需要同步数据。

2、 master接收到psync命令后会进行BGSAVE命令生成RDB文件快照。

3、生成完后,会将RDB文件发送给slave。

4、slave接收到文件会载入RDB快照,并且将数据库状态变更为master在执行BGSAVE时的状态一致。

5、 master会发送保存在缓冲区里的所有写命令,告诉slave可以进行同步了

6、slave执行这些写命令。

2、增量同步

slave已经同步过master了,那么如果后续master进行了写操作,比如说一个简单的set name redis,那么master执行过当前命令后,会将当前命令发送给slave执行一遍,达成数据一致性。

3、重新复制

当slave断开重连之后会进行重新同步,重新同步分完全同步和部分同步。

1、当slave断开重连后,会发送psync 命令给master。

2、master收到psync后会返回+continue回复,表示slave可以执行部分同步了。

3、master发送断线后的写命令给slave

4、slave执行写命令。

# redis三主三从集群检查脚本

#!/bin/bash

function echo_color_green (){
  echo -e "\033[1;32m$1\033[0m"
}

  function echo_color_red (){
  echo -e "\033[1;31m$1\033[0m"
}
function echo_color_yellow (){
  echo -e "\033[1;33m$1\033[0m"
}

function echo_color_blue (){
  echo -e "\033[1;34m$1\033[0m"
}

redis_cli=`find ./ -name 'redis-cli'|head -n 1`
redis_conf=`find ./ -name 'redis.conf'|head -n 1`
host=`less $redis_conf|grep '^bind'| awk '{print $2}'`
port=`less $redis_conf|grep '^port'| awk '{print $2}'`
password=`less $redis_conf|grep '^requirepass'|awk '{print $2}'`

master1_id=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $1}'|sed -n 1p`
master2_id=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $1}'|sed -n 2p`
master3_id=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $1}'|sed -n 3p`
master1_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $2}'|awk -F':' '{print $1}'|sed -n 1p`
master2_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $2}'|awk -F':' '{print $1}'|sed -n 2p`
master3_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep master|awk '{print $2}'|awk -F':' '{print $1}'|sed -n 3p`
master1_slave_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep slave| grep $master1_id |awk '{print $2}'|awk -F':' '{print $1}'`
master2_slave_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep slave| grep $master2_id |awk '{print $2}'|awk -F':' '{print $1}'`
master3_slave_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep slave| grep $master3_id |awk '{print $2}'|awk -F':' '{print $1}'`


if [ $master1_host == $master2_host ];then
    if [ $master1_slave_host == $master3_slave_host ];then
        err_master=$master1_id
    fi
    if [ $master2_slave_host == $master3_slave_host ];then
        err_master=$master2_id
    fi

elif [ $master1_host == $master3_host ];then
    if [ $master1_slave_host == $master2_slave_host ];then
        err_master=$master1_id
    fi
    if [ $master2_slave_host == $master3_slave_host ];then
        err_master=$master3_id
    fi

elif [ $master2_host == $master3_host ];then
    if [ $master1_slave_host == $master3_slave_host ];then
        err_master=$master3_id
    fi
    if [ $master1_slave_host == $master2_slave_host ];then
        err_master=$master2_id
    fi
fi

if [ $err_master ];then
    err_slave_host=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep slave|grep $err_master|awk '{print $2}'|awk -F':' '{print $1}'`
    err_slave_port=`$redis_cli -c -h $host -p $port -a $password cluster nodes 2>/dev/null |grep slave|grep $err_master|awk -F':' '{print $2}'|awk -F'@' '{print $1}'`
    echo_color_red "Redis endpoint $err_slave_host:$err_slave_port need to execute 'CLUSTER FAILOVER'."
    echo_color_blue "Command:"
    echo_color_green "  $redis_cli -c -h $err_slave_host -p $err_slave_port -a $password CLUSTER FAILOVER"
    read -p "是否执行命令(Y/N):" choice
    case $choice in
      y|Y)
      $redis_cli -c -h $err_slave_host -p $err_slave_port -a $password CLUSTER FAILOVER 2>/dev/null
      sleep 5
      echo_color_green "Execute finished.\n"
      $redis_cli --cluster check $host:$port -a $password 2>/dev/null;;
      n|N)
      echo_color_blue "Exit."
      exit;;
      *)
      echo_color_yellow "Input Eror, Exit."
      exit;;
    esac
else
    echo_color_green "Cluster is OK."
fi
编撰人:zhangshuang、wangyxyf、het、admin