redis从节点slave,fail,noaddr问题处理

一、redis集群介绍

      某业务Redis Cluster中一个节点的负载较高,要将其负责的部分slot迁移到另一个节点。查看集群状态时,出现了flags字段为noaddr的标记。

192.168.1.4:2008> cluster nodes

78641a9cf0098e1c5c07821266dcd1feae21bcd3 :0 slave,noaddr - 1530942381678 1530942361875 0 disconnected

2122990aa0f8b5fae63b36d1a598e5194c72c0d0 :0 master,noaddr - 1530943527689 1530943524090 0 disconnected

...

cluster nodes显示的每一行信息,由下面的字段组成。

...

1.1 每个字段的含义如下:

1. id: 节点ID,一个40字节的随机字符串,节点创建时生成,且不会变化(除非使用CLUSTER RESET HARD命令)。

2. ip:port: 客户端访问的地址。

3. flags: 逗号分隔的标记位,可能值有:myself, master, slave, fail?, fail, handshake, noaddr, noflags。

4. master: 若是已知master节点的slave,这里出现的是master的节点ID,否则是"-"。

5. ping-sent: 最近一次发送ping的unix毫秒时间戳,0代表没有发送过。

6. pong-recv: 最近一次收到pong的unix毫秒时间戳。

7. config-epoch: 该节点或其master节点的epoch值。每次故障转移都会生成一个新的,唯一的,递增的epoch值。若多个节点竞争相同的slot,epoch值大的获胜。

8. link-state: 节点和集群总线间的连接状态,可以是connected或disconnected。

9. slot: 该节点负责的slot。

1.2 flags字段各标记含义如下:

myself: 当前连接的节点。

master: 节点是master。

slave: 节点是slave。

fail?: 节点处于pfail状态,当前节点无法和其联系,但其它节点可以。

fail: 节点处于fail状态,大多数节点都无法和其联系,将其由pfail升级到fail状态。

handshake: 还没完全加入集群,正在握手阶段。

noaddr: 不知道节点地址。

noflags: 没有任何标记。

二 问题描述

查看集群状态,发现其中两个从节点异常(是fail状态)

redis从节点slave,fail,noaddr问题处理_第1张图片

在问题节点上查看节点状态,发现它已脱离集群,且id都已发生了变化:

redis从节点slave,fail,noaddr问题处理_第2张图片

即:

id已经从 76ba12f992228d906c368e0a5978013a210e9cd4  变成 af40bb4ce7a4d623a812b716246c30df49b9db08

/*若id没发生变化,直接重启下该从节点就能解决*/

三 解决办法

3.1 将该从节点剔出集群


#在集群每个正常节点上执行cluster forget 故障从节点id,示例:

echo 'cluster forget f86464011d9f8ec605857255c0b67cff1e794c19' | /usr/local/bin/redis-cli -p 6384 -a "密码"

echo 'cluster nodes' | /usr/local/bin/redis-cli -p 6384 -a "密码"

这种方式可能是以前版本的处理方法,我是5.0版本,总是不成功,使用以下方式forget的

redis从节点slave,fail,noaddr问题处理_第3张图片

3.2 重新将该节点加入集群

3.2.1 握手

在集群内任意节点上执行cluster meet命令加入新节点,握手状态会通过信息在集群内传播,这样其他节点会自动发现新节点并发起握手流程。

echo 'cluster meet 192.168.109.132 6383' | /usr/local/bin/redis-cli -p 6384 -a "密码"

3.2.2 配置主从关系

#在该从节上执行cluster replicate 主节点id

[root@centos7-mod ~]# echo 'cluster replicate 2cb35944b4492748a8c739fab63a0e90a56e414a' | /usr/local/bin/redis-cli -p 6383 -a "密码"

Warning: Using a password with '-a' option on the command line interface may not be safe.

OK

3.2.3 检查集群状态

[root@centos7-mod ~]# echo 'cluster nodes' | /usr/local/bin/redis-cli -p 6384 -a "密码"

Warning: Using a password with '-a' option on the command line interface may not be safe.

38287a7e715c358b5537a369646e9698a7583459 192.168.109.132:6383@16383 slave 2cb35944b4492748a8c739fab63a0e90a56e414a 0 1615233239757 8 connected

2cb35944b4492748a8c739fab63a0e90a56e414a 192.168.109.133:6383@16383 master - 0 1615233239000 8 connected 0-5461

0e8fa73711c300f2da6f92df49b215d270021b14 192.168.109.134:6383@16383 slave 00dd345835790608dc062dd4742d853138f06b97 0 1615233241763 9 connected

83780e418e90de6067a196d88a54fd2cfe719f86 192.168.109.134:6384@16384 slave 6a50a9c515acf3490e5a5256250d857d0812bc6a 0 1615233240760 17 connected

00dd345835790608dc062dd4742d853138f06b97 192.168.109.133:6384@16384 master - 0 1615233241000 9 connected 5462-10923

6a50a9c515acf3490e5a5256250d857d0812bc6a 192.168.109.132:6384@16384 myself,master - 0 1615233242000 17 connected 10924-16383

四 redis 集群 noaddr error 恢复脚本

本脚本修复nodes.conf文件丢失而导致的noaddr error,修复此类问题有两种解决办法:

1. 直接修复坏节点的nodes.conf文件,这里不赘述。

2. 通过下面脚本在任意节点上执行,目前不支持所有master都坏的情况。

prepare:将所有的ip用逗号分隔,存入环境变量$ip_group.

执行下列脚本,将password替换:
 

#!/bin/bash
 
ip_group=`echo $ip_group|tr ',' ' '`
password=$1
echo ">> get cluster info..."
for ip in $ip_group
do
    num=`echo cluster nodes | $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password | wc -l`
    if (( $num>1 ));
    then
      cmd_str="echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password"
      bad_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/:0/'|awk  '{print $1}'`
      echo "bad_nodes:"$bad_nodes
 
      master_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/master/'|awk '{print $1}'`
      echo "master_nodes: "$master_nodes
 
      slave_of_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/slave/'|awk '{print $4}'`
      echo "slave_of_nodes: "$slave_of_nodes
	  
	  con_slave_ips=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/slave/'|awk '{print $2}'`
	  echo "con_slave_ips: "$con_slave_ips
	  
      unfrag_slots=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/disconnected/'|awk '/master/'|awk '{print $9}'`
      echo "unfrag_slots: "$unfrag_slots
 
      con_ips=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '{print $2}'`
      echo "con_ips: "$con_ips
 
      break
    fi
done
 
#reassgin master to slave whose master has been down
i=1
echo ">> reassgin master..."
for node in $slave_of_nodes
do
  if [[ $master_nodes =~ $node ]]
  then
    echo "node "$node" has healthy master!"
	i=$i+1
  else
	slave_ip= `echo $con_slave_ips | cut -d ' ' -f $i`
    echo "reassgin master for "$node", ip"$slave_ip
	
    `echo cluster replicate ${master_nodes[0]} | $HOME/bin/redis-cli -h ${slave_ip%:*} -p 6379 -a $password > /dev/null`
	i=$i+1
  fi
done
 
#forget_cluster_nodes
echo ">> cluster forget..."
for ip in $con_ips
do
  echo "ip:"${ip%:*}
  for node in $bad_nodes
  do
    echo "forget node:"$node
    `echo cluster forget $node | $HOME/bin/redis-cli -h ${ip%:*} -p 6379 -a $password >/dev/null `
  done
done
 
#add_new_nodes
echo ">> cluster meet..."
declare -a new_ips_arr
for ip in $ip_group
do
  if [[ $con_ips =~ $ip ]]
  then
    echo "">/dev/null
  else
    echo "new node ip:"${ip%:*}
    new_ips_arr=(${new_ips_arr[@]} ${ip%:*})
    `echo cluster meet ${ip%:*} 6379 | $HOME/bin/redis-cli -h ${con_ips%%:*} -p 6379 -a $password > /dev/null` 
  fi
done
 
#allocate_slots
 
echo ">> cluster add slots..."
unfrag_slots_arr=($unfrag_slots)
for i in ${!unfrag_slots_arr[@]}
do
  low=${unfrag_slots_arr[$i]%-*}
  high=${unfrag_slots_arr[$i]#*-}
  echo "low:"$low",high:"$high
  for ((j=$low;j<=$high;j++))
    do
        `$HOME/bin/redis-cli -h ${new_ips_arr[$i]} -p 6379 -a $password cluster addslots $j > /dev/null`
    done
  echo "unset ip:"${new_ips_arr[$i]}
  unset new_ips_arr[$i]
done
 
#cluster replicate
 
echo ">> cluster replicate..."
tmp_master=`echo $master_nodes|cut -d ' ' -f 1`
sleep 1
for ip in ${new_ips_arr[@]}
do
  echo "cluster replicate for "$ip
  `echo cluster replicate $tmp_master| $HOME/bin/redis-cli -h $ip -p 6379 -a $password > /dev/null` 
done
 

五 移除node脚本内容。

#!/bin/bash

flags_noaddr_node_id="f2c9d6445359372bc7efbe16e53cdaa2d7b38923"

ip_port=$(redis-cli -h 192.168.1.4 -p 2008 cluster nodes | egrep -v 'noaddr|handshake|fail' | awk '{print $2}')

for i in $ip_port
do
  eval $(echo $i | awk -F: '{printf("ip=%s;port=%s",$1,$2)}')

  redis-cli -h $ip -p $port cluster forget $flags_noaddr_node_id

  #flags_noaddr_node_id=$(redis-cli -h $ip -p $port cluster nodes | grep 'noaddr' | awk '{print $1; exit; }')

  #test -n "$flags_noaddr_node_id" && echo $ip, $port, $flags_noaddr_node_id
done

参考:

https://blog.csdn.net/zwj1030711290/article/details/116327840

https://blog.csdn.net/wojiuguowei/article/details/83511023

https://blog.csdn.net/luoww1/article/details/96609233?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-1.base&spm=1001.2101.3001.4242

你可能感兴趣的:(Redis)