Redis数据单节点迁移到集群

利用Redis的持久化文件做迁移是一个不错的注意。 redis重启的时候,会自动从硬盘的持久化文件中读取数据再恢复到内存中。

使用命令bgsave可以得到持久化文件dump.rdb。 使用config set appendonly yes打开appendonly也可以得到appendonly.aof文件。

我在迁移的过程当中也遇到很多问题(持久化文件迁移需要重启pod,重启pod会带来一些问题),总结得出使用redis-dump导出导入数据的最佳实践。 2018-09-07-introduction-to-kubernetes.png

redis-dump的安装

redis-dump是一个第三方的工具,这就意味着需要安装才能使用,它依赖与ruby。 经过踩坑发现对ruby版本还是有要求的,Centos 7.9使用yum info ruby发现版本为2.0.0.648,这个时候你大概率会很麻烦,你需要通过rvm升级ruby而不能简单使用yum进行升级。 如果你有幸和我一样使用Ubuntu 20,你可以使用sudo apt-get install ruby-full直接使用的。

无论如何,还是走rvm安装比较保险一点。

安装 GPG keys:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
#安装 RVM
\curl -sSL https://get.rvm.io | bash -s stable
#source 后才可使用
source /etc/profile.d/rvm.sh
#查看可用的ruby版本
rvm list known
#安装ruby-3.0.0,同时也会安装一些依赖,第一次安装耗时较长。
rvm install ruby-3.0.0
#查看本地已安装的版本
rvm list
#切换版本
rvm use ruby-3.0.0
#查看正在使用的ruby版本
ruby --version
#安装redis-dump
gem install redis-dump -V

至此,已完成安装!

redis-dump的使用

分为数据的导出和数据的导入,以及查看数据

数据导出

1
2
3
4
5
6
#导出所有db
redis-dump -u 127.0.0.1:6379 > db_full.json
#导出db2
redis-dump -u 127.0.0.1:6379 -d 2 > db_db2.json
#设置密码的redis导出,导出某一个db同理
redis-dump -u :PASSWORD@127.0.0.1:6379 > prod.json

清空目标库的数据(可选) redis-cli -h 127.0.0.1 -p 6380 -a mmph_vest01 flushall

数据导入 redis集群也适用,实践发现需要多次导入。*所以不嫌弃麻烦的请往下看!*嫌弃麻烦的话直接多导入几次,验证数据导入成功的方法也要往下看!

1
2
3
4
5
< db_full.json redis-load -u 127.0.0.1:6380
< db_db2.json redis-load -u 127.0.0.1:6380 -d 2
# OR
cat prod.json | redis-load -n -u :PASSWORD@127.0.0.1:6380
cat db_db2.json | redis-load -u 127.0.0.1:6380 -d 2

查看数据

1
2
redis-dump -u :PASSWORD@127.0.0.1:6380 -d 2
#当然也可以接grep查找某一条数据了

Redis Cluster导入数据

在上一步,导出了原redis的数据,现在我们要导入这些数据到集群内。

在上一篇Kubernetes部署Redis集群最佳实践中我们已经知道目前集群数据分片存储在3个主机点上,3个对应的从节点会从主机点复制一份存储。

数据插槽迁移 首先查看集群节点信息

1
2
3
4
5
6
7
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli cluster nodes
80e5692eb146749f7fd7a66e424454862010c1c1 10.0.0.245:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623738439564 1 connected
e9e2058105f3f06d21db9b43aacdcd42e80f0ca4 10.0.0.246:6379@16379 slave c249c43f2afc80f4a471fcf74e13e6e391f8e08b 0 1623738438000 2 connected
299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 10.0.0.243:6379@16379 master - 0 1623738439000 3 connected 10923-16383
c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379@16379 master - 0 1623738440566 2 connected 5461-10922
7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379@16379 myself,master - 0 1623738439000 1 connected 0-5460
64094e0cc464797e447fac1adbb5dc187e131a3c 10.0.0.244:6379@16379 slave 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 0 1623738439000 3 connected

看到

  • 第0-5460的数据插槽在master10.0.0.242
  • 第5461-10922的数据插槽在master10.0.0.165
  • 第10923-16383的数据插槽在master10.0.0.243

数据插槽迁移

我们的任务是先将10.0.0.165上的数据迁移到10.0.0.242上

 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
root@redis-cluster-0:/data# redis-cli --cluster reshard 10.0.0.165 6379
>>> Performing Cluster Check (using node 10.0.0.165:6379)
M: c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 10.0.0.243:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 80e5692eb146749f7fd7a66e424454862010c1c1 10.0.0.245:6379
   slots: (0 slots) slave
   replicates 7062dc79e6bfd5822522ea8b044aebefabfeccd0
S: e9e2058105f3f06d21db9b43aacdcd42e80f0ca4 10.0.0.246:6379
   slots: (0 slots) slave
   replicates c249c43f2afc80f4a471fcf74e13e6e391f8e08b
S: 64094e0cc464797e447fac1adbb5dc187e131a3c 10.0.0.244:6379
   slots: (0 slots) slave
   replicates 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 5462 #输入需要迁出5462个数据卡槽
What is the receiving node ID? 7062dc79e6bfd5822522ea8b044aebefabfeccd0 #接收数据卡槽的id,因为我们要把所以数据迁到10.0.0.242:6379上面,所以这里的id就是10.0.0.242:6379的id
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: c249c43f2afc80f4a471fcf74e13e6e391f8e08b #移出节点id ,因为我们要把10.0.0.165:6379的卡槽迁出去,所以这里的id是10.0.0.165:6379的id 
Source node #2: done #done

Ready to move 5462 slots.
  Source nodes:
    M: c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379
       slots:[5461-10922] (5462 slots) master
       1 additional replica(s)
  Destination node:
    M: 7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379
       slots:[0-5460] (5461 slots) master
       1 additional replica(s)
  Resharding plan:
    Moving slot 5461 from c249c43f2afc80f4a471fcf74e13e6e391f8e08b
    Moving slot 5462 from c249c43f2afc80f4a471fcf74e13e6e391f8e08b
    ......
    ......
    Moving slot 10922 from c249c43f2afc80f4a471fcf74e13e6e391f8e08b
Do you want to proceed with the proposed reshard plan (yes/no)? yes #碎片整理,输入yes
Moving slot 5461 from 10.0.0.165:6379 to 10.0.0.242:6379:
Moving slot 5462 from 10.0.0.165:6379 to 10.0.0.242:6379:
......
......
Moving slot 10922 from 10.0.0.165:6379 to 10.0.0.242:6379:
#完成

再次观察集群节点信息:

1
2
3
4
5
6
7
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli cluster nodes
80e5692eb146749f7fd7a66e424454862010c1c1 10.0.0.245:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623739659111 7 connected
e9e2058105f3f06d21db9b43aacdcd42e80f0ca4 10.0.0.246:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623739660113 7 connected
299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 10.0.0.243:6379@16379 master - 0 1623739661118 3 connected 10923-16383
c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379@16379 master - 0 1623739658110 2 connected
7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379@16379 myself,master - 0 1623739659000 7 connected 0-10922
64094e0cc464797e447fac1adbb5dc187e131a3c 10.0.0.244:6379@16379 slave 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 0 1623739660000 3 connected

看到

  • 第0-10922的数据插槽在master10.0.0.242
  • master10.0.0.165上无数据插槽
  • 第10923-16383的数据插槽在master10.0.0.243

我们用上一个步骤的相同方法再次将10.0.0.243上的数据迁移到10.0.0.242上

1
2
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli --cluster reshard 10.0.0.243 6379
#以上同理

经过两次的数据迁移,现在的状态是三个主节点中只有一个主节点包含所有的数据槽。再次进行验证:

1
2
3
4
5
6
7
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli cluster nodes
80e5692eb146749f7fd7a66e424454862010c1c1 10.0.0.245:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623740188586 7 connected
e9e2058105f3f06d21db9b43aacdcd42e80f0ca4 10.0.0.246:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623740187582 7 connected
299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 10.0.0.243:6379@16379 master - 0 1623740187000 3 connected
c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379@16379 master - 0 1623740188000 2 connected
7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379@16379 myself,master - 0 1623740187000 7 connected 0-16383
64094e0cc464797e447fac1adbb5dc187e131a3c 10.0.0.244:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623740189588 7 connected

正如我们所期待的结果。

数据导出处理

假如你有特别的数据需要导入,例如要将之前的Redis的DB2内的数据导入Redis Cluster,正如我们前面提到的,用redis-dump导出的数据是不能直接导入的,因为redis集群只有一个DB0。 如果不做数据处理而又想导入的话你会被提示:

(key: XXX) ERR SELECT is not allowed in cluster mode

使用sed进行处理,将导入数据库转为db0

1
sed 's/:2,/:0,/g' prod.db2.json

开始导入

现在可以开始导入了

1
2
3
4
5
6
7
cat prod.db2.json | redis-load -n -u 172.21.7.233:6379
#上面的ip可以填service的ip也可以填写主节点的ip
#填写service的ip会提示MOVED到主节点ip
#验证数据导入结果
redis-cli -h 172.21.7.233 -c
172.21.7.233:6379> DBSIZE
(integer) 10918

使用DBSIZE可以看到总的key数量,已经导入成功了。

下面需要将数据槽在均分到另外的两个主节点,步骤同👆。 也可以使用非交互的方式:

1
2
3
4
5
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli --cluster reshard  --cluster-from 7062dc79e6bfd5822522ea8b044aebefabfeccd0 --cluster-to c249c43f2afc80f4a471fcf74e13e6e391f8e08b --cluster-slots 5462 --cluster-yes 10.0.0.242:6379
#将5462个数据插槽划从7062dc79e6bfd5822522ea8b044aebefabfeccd0给c249c43f2afc80f4a471fcf74e13e6e391f8e08b
#也就是从从10.0.0.242:6379到10.0.0.165:6379
kubectl exec -it redis-cluster-0 -n db -- redis-cli --cluster reshard  --cluster-from 7062dc79e6bfd5822522ea8b044aebefabfeccd0 --cluster-to 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 --cluster-slots 5462 --cluster-yes 10.0.0.242:6379
#同理

通过数据划分再次验证

1
2
3
4
5
6
7
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli cluster nodes
80e5692eb146749f7fd7a66e424454862010c1c1 10.0.0.245:6379@16379 slave 299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 0 1623742222275 9 connected
e9e2058105f3f06d21db9b43aacdcd42e80f0ca4 10.0.0.246:6379@16379 slave 7062dc79e6bfd5822522ea8b044aebefabfeccd0 0 1623742221000 7 connected
299d4f8f47b925cc698a34ea4ff9bddba4fae1d2 10.0.0.243:6379@16379 master - 0 1623742219270 9 connected 5462-10923
c249c43f2afc80f4a471fcf74e13e6e391f8e08b 10.0.0.165:6379@16379 master - 0 1623742221274 8 connected 0-5461
7062dc79e6bfd5822522ea8b044aebefabfeccd0 10.0.0.242:6379@16379 myself,master - 0 1623742219000 7 connected 10924-16383
64094e0cc464797e447fac1adbb5dc187e131a3c 10.0.0.244:6379@16379 slave c249c43f2afc80f4a471fcf74e13e6e391f8e08b 0 1623742220272 8 connected

看到数据再一次均分到三个主节点了。

那么dbsize情况呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[kay@BJ-AliYun-HY-WORKER01 kay]$ for x in $(seq 0 5); do     echo "redis-cluster-$x";     kubectl exec redis-cluster-$x -n db -- redis-cli DBSIZE;     echo; done
redis-cluster-0
3606

redis-cluster-1
3647

redis-cluster-2
3665

redis-cluster-3
3647

redis-cluster-4
3665

redis-cluster-5
3606

3606+3647+3665刚好等于之前的(integer) 10918,数据一致。 也可以透过redis-cli --cluster info查看:

1
2
3
4
5
6
[kay@BJ-AliYun-HY-WORKER01 kay]$  kubectl exec -it redis-cluster-0 -n db -- redis-cli --cluster info 10.0.0.243:6379
10.0.0.243:6379 (299d4f8f...) -> 3665 keys | 5462 slots | 1 slaves.
10.0.0.242:6379 (7062dc79...) -> 3606 keys | 5460 slots | 1 slaves.
10.0.0.165:6379 (c249c43f...) -> 3647 keys | 5462 slots | 1 slaves.
[OK] 10918 keys in 3 masters.
0.67 keys per slot on average.

集群状态也是OK的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[kay@BJ-AliYun-HY-WORKER01 kay]$ kubectl exec -it redis-cluster-0 -n db -- redis-cli cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:9
cluster_my_epoch:7
cluster_stats_messages_ping_sent:336751
cluster_stats_messages_pong_sent:415788
cluster_stats_messages_update_sent:42
cluster_stats_messages_sent:752581
cluster_stats_messages_ping_received:361168
cluster_stats_messages_pong_received:347675
cluster_stats_messages_meet_received:5
cluster_stats_messages_update_received:39
cluster_stats_messages_received:708887

至此完成了Redis单节点数据迁移到集群的操作。

总结

持久化文件方式迁移在k8s部署集群的情况下并不是很好用,因为需要重启pod。

而第三方的redis-dump工具是将数据导出为json格式,导入也不需要重启redis。

而如果你在多个db库存储了数据redis-dump的优势是绝对的,需要注意的是需要使用sed先进行处理再进行导入。 因为Redis集群只有DB0是可用的。

大概的步骤总结为:

  1. 单节点redis使用redis-dump导出数据
  2. 使用sed处理数据(如果导出的数据有非db0的)
  3. redis集群数据插槽迁移到一个主节点
  4. 数据导入
  5. 重新划分数据到其他节点

Redis Cluster的收缩以及扩容问题,这里暂时没做了。三主三从的架构足以支撑目前的业务量,后续有需求再补上吧。 本篇结束!

点击刷新🚌