目录
随着业务量的增长,主从复制的redis架构中,单实例的OPS已经接近峰值,很自然想到了数据水平分片。redis 3.0版的一大特性就是支持数据分片的集群功能。集群的特点在于拥有和单机实例同样的性能,同时在网络分区后能够提供一定的可访问性以及对主库故障恢复的支持。哨兵与集群是两个独立的功能,但从特性来看哨兵可以视为集群的子集,当不需要数据分片或者在客户端进行分片的场景下使用哨兵就足够了,但如果需要进行水平扩容,则集群是一个较好的选择。
当一个全新的redis集群已经搭建完成后,需要将原来单实例redis中的数据在线迁移到redis集群中,并且在迁移过程不能影响现有服务,具体需求如下:
为了满足以上需求,经过一番调研,发现redis-migrate-tool工具能胜任此数据迁移工作。
Redis-Migrate-Tool(RMT),是唯品会开源的redis数据迁移工具,主要用于异构redis集群间的数据在线迁移,即数据迁移过程中源集群仍可以正常接受业务读写请求,无业务中断服务时间。目前该项目已经开源在GitHub上(https://github.com/vipshop/redis-migrate-tool)。
RMT具有以下特性:
RMT支持异构redis相互之间的迁移,数据来源可以是:单独的redis实例,twemproxy集群,redis cluster,rdb文件,aof文件。目标可以是:单独的redis实例,twemproxy集群,redis cluster,rdb文件。
RMT启动后模拟成redis slave,请求master的全量数据和增量数据。RMT收到数据之后解析成redis协议格式的oplog(写操作),然后发送给目标库。有两种请求方式,source_safe: true,对于同一ip上的redis,逐个的请求全量数据(RDB);source_safe: false,并行请求同步全量数据。source_safe: false时,需要注意多个源redis所在的同一主机是否有足够的内存和RDB并发落盘时的IOPS性能。
RMT可以帮你从备份的AOF和RDB文件恢复到目标库。
我们建立一个6实例redis集群和一个单实例redis,向单实例redis插入测试数据,然后用redis-migrate-tool将数据迁移至集群中。注意redis-migrate-tool目前不支持redis 4.x,因此本实验使用redis 3.2.3版本。
集群由3节点6实例组成,IP和端口如下:
172.16.1.127:20001、20002
172.16.1.126:20001、20002
172.16.1.125:20001、20002(1)准备配置文件
redis.conf配置文件类似下面的内容,每个实例只有端口不一样:
rename-command flushAll ""
daemonize yes
port 20001
dir "/var/redis/20001"
pidfile "/var/redis/20001/redis.pid"
logfile "/var/redis/20001/redis.log"
dbfilename "dump.rdb"
save 900 1
appendonly no
appendfilename "appendonly.aof"
appendfsync always
maxmemory 1gb
maxmemory-policy volatile-lru
maxmemory-samples 3
slowlog-log-slower-than 10000
repl-backlog-size 64mb
timeout 0
repl-timeout 240
cluster-enabled yes
requirepass "123456"
masterauth "123456"
protected-mode no
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 2gb 1gb 300
(2)启动所有集群实例
在三个节点上分别执行以下命令,共创建6个单实例。
~/redis-3.2.3/src/redis-server /var/redis/20001/redis.conf
~/redis-3.2.3/src/redis-server /var/redis/20001/redis.conf
启动后,可以使用redis命令行客户端连接任意一个节点使用info命令来判断集群是否正常启用了:
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 info cluster
# Cluster
cluster_enabled:1
[root@hdp4/var/redis]#
cluster_enabled为1表示集群正常启用了。现在每个节点都是完全独立的,下面将它们加入同一个集群。
(3)执行redis-trib.rb脚本创建集群
这步需要注意一点,我们的redis设置了密码,因此需要修改redis-trib.rb源码,在“@r = Redis.new”行将密码加入(集群中的所有redis使用同一密码):
@r = Redis.new(:host => @info[:host], :port => @info[:port], :timeout => 60, :password => "123456")
然后执行下面的命令创建集群:
~/redis-3.2.3/src/redis-trib.rb create --replicas 1 172.16.1.127:20001 172.16.1.127:20002 172.16.1.126:20001 172.16.1.126:20002 172.16.1.125:20001 172.16.1.125:20002
其中create参数表示要初始化集群,--replicas 1表示每个主库拥有的从库个数为1,所以整个集群共有3个主库以及3个从库,而主从的节点分配由redis-trib.rb来控制。
(1)准备配置文件
redis.conf配置文件内容如下,之比集群配置文件少了一行cluster-enabled yes:
rename-command flushAll ""
daemonize yes
port 20001
dir "/var/redis/20001"
pidfile "/var/redis/20001/redis.pid"
logfile "/var/redis/20001/redis.log"
dbfilename "dump.rdb"
save 900 1
appendonly no
appendfilename "appendonly.aof"
appendfsync always
maxmemory 1gb
maxmemory-policy volatile-lru
maxmemory-samples 3
slowlog-log-slower-than 10000
repl-backlog-size 64mb
timeout 0
repl-timeout 240
requirepass "123456"
masterauth "123456"
protected-mode no
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 2gb 1gb 300
(2)启动单实例
~/redis-3.2.3/src/redis-server /var/redis/20001/redis.conf
unzip redis-migrate-tool-master.zip
cd redis-migrate-tool-master
autoreconf -fvi
./configure
make
rmt.conf配置文件内容如下:
[source]
type: single
servers :
-172.16.1.124:20001
redis_auth: 123456
[target]
type: redis cluster
servers:
-172.16.1.127:20001
redis_auth: 123456
[common]
listen: 0.0.0.0:8888
其中目标为集群中任意节点即可。
(1)在单实例中生成一些测试key
~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 set foo bar
~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 set foo1 bar1
~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 set key1 123
(2)启动redis-migrate-tool
~/redis-migrate-tool-master/src/redis-migrate-tool -c rmt.conf -o log -d
redis-migrate-tool的监听端口为8888:
[root@hdp1~/redis-migrate-tool-master]#lsof -i:8888
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
redis-mig 126471 root 9u IPv4 137161329 0t0 TCP *:ddi-tcp-1 (LISTEN)
[root@hdp1~/redis-migrate-tool-master]#
(3)查看集群数据
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 get foo
(error) MOVED 12182 172.16.1.125:20001
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -h 172.16.1.125 -p 20001 -a 123456 get foo
"bar"
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 get foo1
(error) MOVED 13431 172.16.1.125:20001
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -h 172.16.1.125 -p 20001 -a 123456 get foo1
"bar1"
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -p 20001 -a 123456 get key1
(error) MOVED 9189 172.16.1.126:20001
[root@hdp4/var/redis]#~/redis-3.2.3/src/redis-cli -h 172.16.1.126 -p 20001 -a 123456 get key1
"123"
[root@hdp4/var/redis]#
可以看到,3个测试key都复制到了集群。以后在单实例上的任何数据变动都会复制到集群中。(4)观察迁移状态
使用redis-cli可以连接 rmt.conf 中配置的端口,执行info命令,就可以观察迁移的状态。total_msgs_outqueue可以判断是否有oplog在队列中等待处理,如果total_msgs_outqueue>0,请继续等待。
[root@hdp1~/redis-migrate-tool-master]#~/redis-3.2.3/src/redis-cli -p 8888 info
# Server
version:0.1.0
os:Linux 3.10.0-327.el7.x86_64 x86_64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:126471
tcp_port:8888
uptime_in_seconds:141
uptime_in_days:0
config_file:/root/redis-migrate-tool-master/rmt.conf
# Clients
connected_clients:1
max_clients_limit:100
total_connections_received:2
# Memory
mem_allocator:jemalloc-4.0.4
# Group
source_nodes_count:1
target_nodes_count:3
# Stats
all_rdb_received:1
all_rdb_parsed:1
all_aof_loaded:0
rdb_received_count:1
rdb_parsed_count:1
aof_loaded_count:0
total_msgs_recv:3
total_msgs_sent:3
total_net_input_bytes:305
total_net_output_bytes:96
total_net_input_bytes_human:305B
total_net_output_bytes_human:96B
total_mbufs_inqueue:0
total_msgs_outqueue:0
[root@hdp1~/redis-migrate-tool-master]#
(5)检验集群和目标的差异
[root@hdp1~/redis-migrate-tool-master]#src/redis-migrate-tool -c rmt.conf -o log -C "redis_check 10000"
Check job is running...
Checked keys: 10000
Inconsistent value keys: 0
Inconsistent expire keys : 0
Other check error keys: 0
Checked OK keys: 10000
All keys checked OK!
Check job finished, used 0.136s
[root@hdp1~/redis-migrate-tool-master]#
如果是异构集群的迁移,更改redis驱动/客户端和修改代码,重新发布是必然的事情。如果是同构集群,做配置发布就可以。如果没有做重启发布,等待源集群没有连接之后,可以关闭REDIS-MIGRATE-TOOL进程(kill或在redis-cli shutdown)。或者重启应用,强制断开长连接。