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

梦里梦外; 2022-09-08 05:54 126阅读 0赞

#

一、redis集群介绍

  1. 某业务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状态)

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3ajEwMzA3MTEyOTA_size_16_color_FFFFFF_t_70

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

20210501112903379.png

即:

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的

20210501131816239.png

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替换:

  1. #!/bin/bash
  2. ip_group=`echo $ip_group|tr ',' ' '`
  3. password=$1
  4. echo ">> get cluster info..."
  5. for ip in $ip_group
  6. do
  7. num=`echo cluster nodes | $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password | wc -l`
  8. if (( $num>1 ));
  9. then
  10. cmd_str="echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password"
  11. bad_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/:0/'|awk '{print $1}'`
  12. echo "bad_nodes:"$bad_nodes
  13. master_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/master/'|awk '{print $1}'`
  14. echo "master_nodes: "$master_nodes
  15. slave_of_nodes=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/slave/'|awk '{print $4}'`
  16. echo "slave_of_nodes: "$slave_of_nodes
  17. con_slave_ips=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '/slave/'|awk '{print $2}'`
  18. echo "con_slave_ips: "$con_slave_ips
  19. unfrag_slots=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/disconnected/'|awk '/master/'|awk '{print $9}'`
  20. echo "unfrag_slots: "$unfrag_slots
  21. con_ips=`echo cluster nodes| $HOME/bin/redis-cli -h ${ip} -p 6379 -a $password|awk '/ connected/'|awk '{print $2}'`
  22. echo "con_ips: "$con_ips
  23. break
  24. fi
  25. done
  26. #reassgin master to slave whose master has been down
  27. i=1
  28. echo ">> reassgin master..."
  29. for node in $slave_of_nodes
  30. do
  31. if [[ $master_nodes =~ $node ]]
  32. then
  33. echo "node "$node" has healthy master!"
  34. i=$i+1
  35. else
  36. slave_ip= `echo $con_slave_ips | cut -d ' ' -f $i`
  37. echo "reassgin master for "$node", ip"$slave_ip
  38. `echo cluster replicate ${master_nodes[0]} | $HOME/bin/redis-cli -h ${slave_ip%:*} -p 6379 -a $password > /dev/null`
  39. i=$i+1
  40. fi
  41. done
  42. #forget_cluster_nodes
  43. echo ">> cluster forget..."
  44. for ip in $con_ips
  45. do
  46. echo "ip:"${ip%:*}
  47. for node in $bad_nodes
  48. do
  49. echo "forget node:"$node
  50. `echo cluster forget $node | $HOME/bin/redis-cli -h ${ip%:*} -p 6379 -a $password >/dev/null `
  51. done
  52. done
  53. #add_new_nodes
  54. echo ">> cluster meet..."
  55. declare -a new_ips_arr
  56. for ip in $ip_group
  57. do
  58. if [[ $con_ips =~ $ip ]]
  59. then
  60. echo "">/dev/null
  61. else
  62. echo "new node ip:"${ip%:*}
  63. new_ips_arr=(${new_ips_arr[@]} ${ip%:*})
  64. `echo cluster meet ${ip%:*} 6379 | $HOME/bin/redis-cli -h ${con_ips%%:*} -p 6379 -a $password > /dev/null`
  65. fi
  66. done
  67. #allocate_slots
  68. echo ">> cluster add slots..."
  69. unfrag_slots_arr=($unfrag_slots)
  70. for i in ${!unfrag_slots_arr[@]}
  71. do
  72. low=${unfrag_slots_arr[$i]%-*}
  73. high=${unfrag_slots_arr[$i]#*-}
  74. echo "low:"$low",high:"$high
  75. for ((j=$low;j<=$high;j++))
  76. do
  77. `$HOME/bin/redis-cli -h ${new_ips_arr[$i]} -p 6379 -a $password cluster addslots $j > /dev/null`
  78. done
  79. echo "unset ip:"${new_ips_arr[$i]}
  80. unset new_ips_arr[$i]
  81. done
  82. #cluster replicate
  83. echo ">> cluster replicate..."
  84. tmp_master=`echo $master_nodes|cut -d ' ' -f 1`
  85. sleep 1
  86. for ip in ${new_ips_arr[@]}
  87. do
  88. echo "cluster replicate for "$ip
  89. `echo cluster replicate $tmp_master| $HOME/bin/redis-cli -h $ip -p 6379 -a $password > /dev/null`
  90. done

五 移除node脚本内容。

  1. #!/bin/bash
  2. flags_noaddr_node_id="f2c9d6445359372bc7efbe16e53cdaa2d7b38923"
  3. ip_port=$(redis-cli -h 192.168.1.4 -p 2008 cluster nodes | egrep -v 'noaddr|handshake|fail' | awk '{print $2}')
  4. for i in $ip_port
  5. do
  6. eval $(echo $i | awk -F: '{printf("ip=%s;port=%s",$1,$2)}')
  7. redis-cli -h $ip -p $port cluster forget $flags_noaddr_node_id
  8. #flags_noaddr_node_id=$(redis-cli -h $ip -p $port cluster nodes | grep 'noaddr' | awk '{print $1; exit; }')
  9. #test -n "$flags_noaddr_node_id" && echo $ip, $port, $flags_noaddr_node_id
  10. 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

发表评论

表情:
评论列表 (有 0 条评论,126人围观)

还没有评论,来说两句吧...

相关阅读