Redis集群添加节点之后数据重新均匀分配
# redis 5 cluster集群增加节点动态扩容的步骤
已有集群为6个节点3组主从节点
10.10.10.42:9002
10.10.10.42:9003
10.10.10.41:9002
10.10.10.43:9003
10.10.10.41:9001
10.10.10.43:9001
1
2
3
4
5
6
2
3
4
5
6
现要增加第4组主从节点
10.10.10.42:9005
10.10.10.41:9004
1
2
2
新增节点
创建一个新的主节点
10.10.10.41:9004
命令里需要指定一个已有节点以便于获取集群信息,(新增节点在前,已有节点在后)该命令添加的节点默认一个主节点,但是没有分配slot,也没有key./data/redis/redis9001/bin/redis-cli -h 10.10.10.41 -p 9001 -a passwordxcxxxx --cluster add-node 10.10.10.41:9004 10.10.10.41:9001
1将
10.10.10.42:9005
创建为10.10.10.41:9004
的从节点。因为,集群会自动为从节点数最少的主节点创建从节点,所以这里不需要指定主节点。/data/redis/redis9001/bin/redis-cli -a 'passwordxcxxxx' --cluster add-node 10.10.10.42:9005 10.10.10.41:9001 --cluster-slave
1
# Slot 数据迁移到新节点(一定要在业务低峰期操作)
三个主节点的slot分布:主节点1: [0-5460],主节点2: [5461-10922],主节点3: [10923-16383]
预计分配之后的slot: 主节点1[0-4095],节点2:[6144-10922] 节点3:[12288-16383],主节点4:[4096-6144] +[10922-12288]
10.10.10.42:9002 slots:[0-5460] (5461 slots) master
10.10.10.41:9001 slots:[5461-10922] (5462 slots) master
10.10.10.43:9001 slots:[10923-16383] (5461 slots) master
1
2
3
2
3
快速迁移 cluster reshard
(业务繁忙时不建议使用)
# 指定迁移1365个slot迁移到新节点
/data/redis/redis9001/bin/redis-cli -a passwd123454 --cluster reshard 10.10.10.41:9001 --cluster-from 6f7c25fc85f5e66484ea6679d5220dcaed5f3672 --cluster-to 26319656b03d9238839187ea2a074cf54e239ecf --cluster-slots 1365 --cluster-yes
1
2
2
#!/bin/sh
# Writed by yijian on 2020/8/10
# 迁移 slot 工具,多个slot迁移
#
# 使用时,需要指定如下几个参数:
# 1)参数1:必选参数,用于指定源节点(格式为:ip:port)
# 2)参数2:必选参数,用于指定目标节点(格式为:ip:port)
# 3)参数3:可选参数,用于指定访问 redis 的密码
# 4)参数4:开始slot
# 5)参数5:结束slot
#
# 使用示例(将2020从10.9.12.8:1383迁移到10.9.12.9:1386):
# move_redis_slot.sh 2020 10.9.12.8:1383 10.9.12.9:1386
#
# 执行本脚本时,有两个“确认”,
# 第一个“确认”是提示参数是否正确,
# 第二个“确认”是提示是否迁移已有的keys,
# 如果输入非yes则只迁移slot,不迁移已有keys。
# 确保redis-cli可用
REDIS_CLI=${REDIS_CLI:-redis-cli}
#REDIS_CLI="/usr/local/bin/redis-cli"
which "$REDIS_CLI" >/dev/null 2>&1
if test $? -ne 0; then
echo "\`redis-cli\` not exists or not executable"
exit 1
fi
# 参数检查
if test $# -ne 4 -a $# -ne 5; then
echo -e "Usage: $(basename $0) source_node destition_node redis_password \033[1;33mbegin end\033[m"
echo -e "Example1: $(basename $0) 127.0.0.1:6379 127.0.0.1:6380 \033[1;33m450 460\033[m"
echo -e "Example2: $(basename $0) 127.0.0.1:6379 127.0.0.1:6380 password123456 \033[1;33m450 460\033[m"
exit 1
fi
# SLOT=$1
SRC_NODE="$1"
DEST_NODE="$2"
REDIS_PASSOWRD="$3"
BEGIN_SLOT="$4"
END_SLOT="$5"
# 得到指定节点的 nodeid
function get_node_id() {
node="$1"
node_ip="$(echo $node | cut -d':' -f1)"
node_port=$(echo $node | cut -d':' -f2)
# 得到对应的 nodeid
$REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $node_ip -p $node_port \
CLUSTER NODES | awk -v node=$node -F'[ @]' '{if ($2==node) printf("%s",$1);}'
}
SRC_NODE_ID="$(get_node_id $SRC_NODE)"
SRC_NODE_IP="$(echo $SRC_NODE | cut -d':' -f1)"
SRC_NODE_PORT=$(echo $SRC_NODE | cut -d':' -f2)
DEST_NODE_ID="$(get_node_id $DEST_NODE)"
DEST_NODE_IP="$(echo $DEST_NODE | cut -d':' -f1)"
DEST_NODE_PORT=$(echo $DEST_NODE | cut -d':' -f2)
echo -e "\033[1;33mSource\033[m node: $SRC_NODE_IP:$SRC_NODE_PORT($SRC_NODE_ID)"
echo -e "\033[1;33mDestition\033[m node: $DEST_NODE_IP:$DEST_NODE_PORT($DEST_NODE_ID)"
if test -z "$SRC_NODE_ID"; then
echo -e "Can not get the source node ID of \033[1;33m$SRC_NODE\033[m"
exit 1
fi
if test -z "$DEST_NODE_ID"; then
echo -e "Can not get the destition node ID of \033[1;33m$DEST_NODE\033[m"
exit 1
fi
echo -en "Confirm to continue? [\033[1;33myes\033[m/\033[1;33mno\033[m]"
read -r -p " " input
if test "$input" != "yes"; then
exit 1
fi
echo "........."
# 目标节点上执行 IMPORTING 操作
# 如果 $SLOT 已在目标节点,则执行时报错“ERR I'm already the owner of hash slot 1987”
echo -e "\033[1;33mImporting\033[m $BEGIN_SLOT $END_SLOT from $SRC_NODE($SRC_NODE_ID) to $DEST_NODE($DEST_NODE_ID) ..."
for ((SLOT = ${BEGIN_SLOT}; SLOT <= ${END_SLOT}; SLOT++)); do
err=$($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $DEST_NODE_IP -p $DEST_NODE_PORT \
CLUSTER SETSLOT $SLOT IMPORTING $SRC_NODE_ID)
echo "${SLOT}"
if test "X$err" != "XOK"; then
echo "[destition://$DEST_NODE_IP:$DEST_NODE_PORT] $err"
exit 1
fi
done
# 源节点上执行 MIGRATING 操作
# 如果 $SLOT 并不在源节点上,则执行时报错“ERR I'm not the owner of hash slot 1987”
echo -e "\033[1;33mMigrating\033[m $BEGIN_SLOT $END_SLOT from $SRC_NODE($SRC_NODE_ID) to $DEST_NODE($DEST_NODE_ID) ..."
for ((SLOT = ${BEGIN_SLOT}; SLOT <= ${END_SLOT}; SLOT++)); do
err=$($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $SRC_NODE_IP -p $SRC_NODE_PORT \
CLUSTER SETSLOT $SLOT MIGRATING $DEST_NODE_ID)
echo "${SLOT}"
if test "X$err" != "XOK"; then
echo "[source://$SRC_NODE_IP:$SRC_NODE_PORT] $err"
exit 1
fi
done
# 是否迁移已有的keys?
echo -en "Migrate keys in slot://$BEGIN_SLOT $END_SLOT? [\033[1;33myes\033[m/\033[1;33mno\033[m]"
read -r -p " " input
if test "$input" = "yes"; then
first=1 # 是否第一轮keys迁移操作
batch=1000 # 一次批量迁移的keys数
timeout_ms=60000 # 超时时长(单位:毫秒)
destination_db=0 # 对于redis集群,取值总是为0
num_keys=0
echo "........."
echo -e "Migrating keys in slot://$BEGIN_SLOT $END_SLOT ..."
while true; do
# 在源节点上执行:
# 借助命令“CLUSTER GETKEYSINSLOT”和命令“MIGRATE”迁移已有的keys
for ((SLOT = ${BEGIN_SLOT}; SLOT <= ${END_SLOT}; SLOT++)); do
keys="$($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $SRC_NODE_IP -p $SRC_NODE_PORT \
CLUSTER GETKEYSINSLOT $SLOT $batch | tr '\n' ' ' | xargs)"
if test -z "$keys"; then
if test $first -eq 1; then
echo -e "No any keys to migrate in slot://$SLOT"
else
echo -e "Finished migrating all keys (\033[1;33m$num_keys\033[m) in slot://$SLOT"
fi
break 2
fi
first=0
n=$(echo "$keys" | tr -cd ' ' | wc -c)
num_keys=$(($num_keys + $n))
#echo -e "(\033[1;33m$n\033[m)$keys"
# 在源节点上执行命令“MIGRATE”迁移到目标节点
# MIGRATE returns OK on success,
# or NOKEY if no keys were found in the source instance
if test -z "$REDIS_PASSOWRD"; then
err=$($REDIS_CLI --raw \
-h $SRC_NODE_IP -p $SRC_NODE_PORT \
MIGRATE $DEST_NODE_IP $DEST_NODE_PORT "" $destination_db $timeout_ms \
REPLACE KEYS $keys)
else
err=$($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $SRC_NODE_IP -p $SRC_NODE_PORT \
MIGRATE $DEST_NODE_IP $DEST_NODE_PORT "" $destination_db $timeout_ms \
REPLACE AUTH "$REDIS_PASSOWRD" KEYS $keys)
fi
if test "X$err" = "XNOKEY"; then
break
fi
echo -e "\033[1;33m$n\033[m keys migratd"
done
done
fi
# 取得所有 master 节点
nodes=($($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" -h $DEST_NODE_IP -p $DEST_NODE_PORT \
CLUSTER NODES | awk '{if (match($3,"master")) printf("%s\n",$2);}'))
# 在所有 master 节点上执行 NODE 操作
# 实际上,只可对源节点和目标节点执行 NODE 操作,
# 新的配置会自动在集群中传播。
echo "........."
for node in ${nodes[*]}; do
node_ip="$(echo $node | cut -d':' -f1)"
node_port=$(echo $node | cut -d':' -f2)
echo -en "NODE: $node_ip:$node_port "
for ((SLOT = ${BEGIN_SLOT}; SLOT <= ${END_SLOT}; SLOT++)); do
err=$($REDIS_CLI --raw --no-auth-warning -a "$REDIS_PASSOWRD" \
-h $node_ip -p $node_port \
CLUSTER SETSLOT $SLOT NODE $DEST_NODE_ID)
echo -e "\033[1;33m$err\033[m"
done
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#从10.10.10.42:9002迁移[4095到5460共1365]个slots到新的主节点10.10.10.41:9004
#最好多次少量迁移 [4095 4595],[4596 5095],[5096 5460]
sudo sh /tmp/redis_slot_move_more.sh 10.10.10.42:9002 10.10.10.41:9004 password123456 4096 5460
#从10.10.10.41:9001迁移[5461到6826共1365]个slots到新的主节点10.10.10.41:9004
sudo sh /tmp/redis_slot_move_more.sh 10.10.10.41:9001 10.10.10.41:9004 password123456 5461 6144
#从10.10.10.43:9001迁移[10923到12288共1365]个slots到新的主节点10.10.10.41:9004
sudo sh /tmp/redis_slot_move_more.sh 10.10.10.43:9001 10.10.10.41:9004 password123456 10922 12288
1
2
3
4
5
6
7
2
3
4
5
6
7
若出现警告,则手动执行即可 cluster setslot 11763 stable
Check for open slots...
[WARNING] Node 172.31.92.83:8001 has slots in importing state 11763.
[WARNING] The following slots are open: 11763.
#解决:
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
172.31.92.83:8001> cluster setslot 11763 stable
OK
再执行 check
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
上次更新: 8/28/2024
- 01
- GPT分区使用 parted 扩展分区的操作流程 原创08-28
- 02
- VictoriaMetrics 集群版安装与配置 原创08-24
- 03
- Kubernetes (k8s) 相关名词详解 原创06-27