目录

1、知识准备

1.1 Slave的选举与提升

1.2 主从切换命令

2、方案规划

2.1 redis-cluster模式

2.2 redis-proxy模式

3、安装部署

3.1 实验准备

3.2 编译redis

3.3 配置redis

3.4 启动redis

3.5 搭建集群

3.6 安装proxy

4、灾备方案

4.1 机房出现故障

4.2 单个master宕机

4.3 切换脚本切换

4.4 手工切换

4.4.1 主从切换

4.4.2 灾备切换


1、知识准备

1.1 Slave的选举与提升

当slaves节点进行选举时,会在其他masters的帮助下进行投票,选举出一个slave并提升为master。当master处于FAIL状态时,将会触发slave的选举。slaves都希望将自己提升为master, 此master的所有slaves都可以开启选举,不过最终只有一个slave获胜。具体的选举与提升流程如下:

① 满足如下情况slave即可进行选举:

1)当此slave的master处于FAIL状态;

2)此master持有非零个slots;

3)此slave的replication链接与master断开时间没有超过设定值,为了确保此被提升的slave的数据是新鲜的,这个时间用户可以配置。

②slave自增它的currentEpoch值,然后向其他masters请求投票(需求支持,votes)。slave通过向其他masters传播“FAILOVER_AUTH_REQUEST”数据包,然后最长等待2倍的NODE_TIMEOUT时间,来接收反馈。(在集群node创建时,master和slave都会将各自的currentEpoch设置为0,每次从其他node接收到数据包时,如果发现发送者的epoch值比自己的大,那么当前node将自己的currentEpoch设置为发送者的epoch,最终所有的nodes都会认同集群中最大的epoch值;当集群的状态变更,或者node为了执行某个行为需求agreement时,都将需要epoch(传递或者比较)。)

③一旦一个master向此slave投票,将会响应“FAILOVER_AUTH_ACK”,此后在2 * NODE_TIMOUT时间内,它将不会向同一个master的slaves投票;虽然这对保证安全上没有必要,但是对避免多个slaves同时选举时有帮助的。slave将会丢弃那些epoch值小于自己的currentEpoch的AUTH_ACK反馈,即不会对上一次选举的投票计数(只对当前轮次的投票计数)

④一旦此slave获取了大多数master的ACKs,它将在此次选举中获胜;否则如果大多数master不可达(在2 * NODE_TIMEOUT)或者投票额不足,那么它的选举将会被中断,那么其他的slave将会继续尝试。

1.2 主从切换命令

cluster failover [force|takeover]命令解析

该命令只能在群集slave节点执行,让slave节点进行一次人工故障切换。 人工故障切换是预期的操作,而非发生了真正的故障,目的是以一种安全的方式(数据无丢失)将当前master节点和其中一个slave节点(执行cluster-failover的节点)交换角色。

【 cluste failover】

当该slave节点执行 cluster failover命令时,(将切换为新master节点)处理完来自master的所有复制,客户端的访问将会自动由原master节点切换至新master节点。处理的具体流程如下:

1. 当前slave节点告知其master节点停止处理来自客户端的请求

2. master 节点将当前replication offset 回复给该slave节点

3. 该slave节点在未应用至replication offset之前不做任何操作,以保证master传来的数据均被处理。

4. 该slave 节点进行故障转移,从群集中大多数的master节点获取epoch,然后广播自己的最新配置

5. 原master节点收到配置更新:解除客户端的访问阻塞,回复重定向信息,以便客户端可以和新master通信。

【 cluste failover force】

slave节点不和master协商(master也许已不可达),从上如4步开始进行故障切换。当master已不可用,而我们想要做人工故障转移时,该选项很有用。但是,即使使用FORCE选项,我们依然需要群集中大多数master节点有效,以便对这次切换进行验证,同时为将成为新master的salve节点生成新的配置epoch。

特点:忽略主备同步的状态,设置mf_can_start = 1,标记failover开始。

【 cluste failover takeover】

TAKEOVER选项 实现了FORCE的所有功能,同时为了能够进行故障切换放弃群集验证。当slave节点收到命令CLUSTER FAILOVER TAKEOVER会做如下操作:

1. 独自生成新的configEpoch,若本地配置epoch非最大的,则取当前有效epoch值中的最大值并自增作为新的配置epoch。

2. 将原master节点管理的所有哈希槽分配给自己,同时尽快分发最新的配置给所有当前可达节点,以及后续恢复的故障节点,期望最终配置分发至所有节点。

特点:忽略主备同步,忽略集群其他master的投票。

参考文献:cluster-failover 命令 -- Redis中国用户组(CRUG)

2、方案规划

2.1 redis-cluster模式

redis-cluster模式架构图如下:


架构说明:

1、redis-cluster采用了同城双活架构,AZ1和AZ2分别为可用区1、可用区2,主节点(AZ1)按3主3从部署,备节点(AZ2)作为Cluster的6从,整个集群为3主9从;

2、单个master节点发生故障,redis集群自动感知并进行选主,完成主从切换,不影响业务正常使用;

3、应用服务连接所有Redis集群主从节点,以便自动感知主从切换情况。其实只要连接到redis集群一个节点,应用服务便可以获取到集群信息,从而获取主从切换情况,建议还是把所有节点都配置上,防止某些节点宕机后读取不了节点信息而报错。

注意:

1、单AZ1池资源出现问题,可能导致redis集群进入fail状态,可以使用已准备好的脚本进行快速切换AZ2节点,完成集群恢复。可以考虑把master节点打散到两个AZ,避免集群超半数master节点宕机;

2.2 redis-proxy模式

        redis-proxy模式采用官方的redis-proxy+cluster模式,优点就是应用只需要连接proxy节点即可,不需要配置更多的node节点,生产环境proxy需要考虑高可用,而proxy也可以考虑用lvs+keepalived作为代理取代,架构图如下所示:

3、安装部署

3.1 实验准备

配置

IP

系统

redis版本

2C8G

172.16.0.8

centos7.6

redis6.2.7

3.2 编译redis

下载对应版本的redis(下载地址:Index of /releases/)

wget  http://download.redis.io/releases/redis-6.2.7.tar.gz

编译安装redis

tar xf redis-6.2.7.tar.gz  && cd redis-6.2.7/
make && make install

3.3 配置redis

在/data/redis/目录下创建文件7001

mkdir -p  /data/redis && cd /data/redis
mkdir -p {7001..7006}

在7001文件夹下创建相当于文件夹

cd /data/redis/7001
mkdir -p bin  conf  data  logs  redis-cluster
cd bin
cp -r /usr/local/bin/redis-*  ./
编写启动redis脚本redis.sh
#!/bin/bash
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

REDIS_HOME="/data/redis/7001"
EXEC="$REDIS_HOME/bin/redis-server"
CLIEXEC="$REDIS_HOME/bin/redis-cli"
CONF="$REDIS_HOME/conf/redis.conf"
REDISPORT=$(awk '/^port/{print $2}' $CONF)
PIDFILE=$(awk '/^pidfile/{print $2}' $CONF)

start() {
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $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
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi

}

restart() {

        stop
        sleep 1
        start
}

case "$1" in
    start)
        start;;
    stop)
        stop;;
    restart)
        restart;;
esac
chmod +x redis.sh

编制redis.conf配置文件

protected-mode no
port 7001
maxmemory 1gb
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile "/data/redis/7001/redis_7001.pid"
loglevel notice
logfile "/data/redis/7001/logs/redis.log"
databases 16
always-show-logo yes
save ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename "dump.rdb"
dir "/data/redis/7001/data"
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 10
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
cluster-enabled yes
cluster-config-file "/data/redis/7001/redis-cluster/nodes-7001.conf"
cluster-node-timeout 5000
slowlog-log-slower-than 10000
slowlog-max-len 10000
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4kb
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
把7001文件夹复制到其他文件夹,并将7001端口改成其他的
cd  /data/redis 
rm -rf {7002..7006}
cp -r 7001  7002  
cp -r 7001  7003
cp -r 7001  7004
cp -r 7001  7005
cp -r 7001  7006

修改bin/redis.sh配置文件夹位置

sed -i 's/7001/7002/g' /data/redis/7002/bin/redis.sh
sed -i 's/7001/7003/g' /data/redis/7003/bin/redis.sh
sed -i 's/7001/7004/g' /data/redis/7004/bin/redis.sh
sed -i 's/7001/7005/g' /data/redis/7005/bin/redis.sh
sed -i 's/7001/7006/g' /data/redis/7006/bin/redis.sh
修改conf/redis.conf配置端口
sed -i 's/7001/7002/g' /data/redis/7002/conf/redis.conf
sed -i 's/7001/7003/g' /data/redis/7003/conf/redis.conf
sed -i 's/7001/7004/g' /data/redis/7004/conf/redis.conf
sed -i 's/7001/7005/g' /data/redis/7005/conf/redis.conf
sed -i 's/7001/7006/g' /data/redis/7006/conf/redis.conf
 

3.4 启动redis

启动redis命令

/data/redis/7001/bin/redis.sh  start
/data/redis/7002/bin/redis.sh  start
/data/redis/7003/bin/redis.sh  start
/data/redis/7004/bin/redis.sh  start
/data/redis/7005/bin/redis.sh  start
/data/redis/7006/bin/redis.sh  start

检查redis是否已经启动

ps aux | grep redis

3.5 搭建集群

搭建redis-cluster集群,中间有提示,输入“yes”

/data/redis/7001/bin/redis-cli --cluster create 172.16.0.8:7001  172.16.0.8:7002 172.16.0.8:7003 172.16.0.8:7004  172.16.0.8:7005 172.16.0.8:7006 --cluster-replicas 1 

3.6 安装proxy

centos7默认是4.8,redis-cluster-proxy需要4.9以上版本GCC

yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
下载安装redis cluster proxy(https://github.com/RedisLabs/redis-cluster-proxy/tree/1.0
yum -y install git
git clone https://github.com/RedisLabs/redis-cluster-proxy.git
cd redis-cluster-proxy
make && make install
配置redis-cluster-proxy
mkdir -p  /data/redis/proxy/{conf,bin,logs}
cp -r src/redis-cluster-proxy  /data/redis/proxy/bin

编写redis-cluster-proxy配置文件/data/redis/proxy/conf/proxy.conf

cluster 172.16.0.14:7001
cluster 172.16.0.14:7002
cluster 172.16.0.14:7003
cluster 172.16.0.14:7004
cluster 172.16.0.14:7005
cluster 172.16.0.14:7006
port 7000
bind 0.0.0.0
threads 8
logfile "/data/redis/proxy/logs/redis_cluster_proxy.log"
enable-cross-slot yes

启动redis-cluster-proxy

nohup /data/redis/proxy/bin/redis-cluster-proxy -c /data/redis/proxy/conf/proxy.conf > /data/redis/proxy/logs/proxy.log 2>&1 &

4、灾备方案

4.1 机房出现故障

最开始cluster搭建方式如下图所示

在AZ1机房全部宕机后,我们需要通过执行cluster failover takeover命令将AZ2机房切换为Master,如下图所示:

在AZ1机房恢复正常之后,如下图所示:

4.2 单个master宕机

在某个Master宕机后,集群会自动主从切换,需要检测哪个Slave成为了Master

如果是AZ2的Salve成为Master,使用命令cluster failover在AZ1的Slave上执行,让其成为Master;

如果是AZ1的Slave成为了Master,就不需要进行操作;

4.3 切换脚本切换

redis_check.sh脚本为检测redis节点是否存活

#!/bin/bash 

LOGDIR="/root"
BINDIR="/data/redis/7001/bin/redis-cli"
PASSWD="123456"
IPDIR="172.16.0.8:7001  172.16.0.8:7002 172.16.0.8:7003 172.16.0.8:7004  172.16.0.8:7005 172.16.0.8:7006" 
DATE=`date`
LOGFILE=${LOGDIR}/logs
ERROR_LOG=${LOGDIR}/error.logs

cd ${LOGDIR}
if [ ! -d bak ] ; then
        mkdir -p bak
fi

for i in $IPDIR
do
  port=${i#*:}
  ip=${i%:*}

  ALIVE=`$BINDIR -h $ip -p $port  PING`
  #ALIVE=`$BINDIR -h $ip -p $port -a $PASSWD PING`

  if [ "$ALIVE" == "PONG" ]; then
    echo "${DATE} Success: redis-cli -h $ip -p $port   PING $ALIVE" >> $LOGFILE 2>&1
  else
    echo "${DATE} Failed:redis-cli -h $ip -p $port  PING $ALIVE " >> $ERROR_LOG 2>&1
  fi

done
 

redis_task.sh为AZ1节点宕机后,执行脚本切换到AZ2节点

#!/bin/bash

IPMASTER="172.16.0.8:7001  172.16.0.8:7002 172.16.0.8:7003"
BINDIR="/data/redis/7001/bin/redis-cli"
PASSWD="123456"
DATE=`date`
LOGDIR="/root"
LOGFILE=${LOGDIR}/logs
ERROR_LOG=${LOGDIR}/error.logs

for i in $IPMASTER
do
  port=${i#*:}
  ip=${i%:*}

  status=`$BINDIR -h $ip -p $port -c cluster failover takeover`
  #status=` $BINDIR -h $ip -p $port -a $PASSWD -c cluster failover takeover`
 
  if [ "$status" == "OK" ]; then
    echo "${DATE} Success: $i 成功切换成master节点" >> $LOGFILE 2>&1
  else
    echo "${DATE} Failed: $i 切换master节点失败 " >> $ERROR_LOG 2>&1
  fi

done
 

4.4 手工切换

4.4.1 主从切换

进入需要切换的从节点

127.0.0.1:7005> CLUSTER FAILOVER
OK
 

如果不小心登录到了主节点,也没有关系,节点会提示如下错误

127.0.0.1:7001> CLUSTER FAILOVER
(error) ERR You should send CLUSTER FAILOVER to a replica

如果不想进去集群,可以输入以下命令

redis-cli -p 7001 -c CLUSTER FAILOVER

4.4.2 灾备切换

redis-cli -p 7004 -c cluster failover takeover

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐