30

Redis 数据迁移至 Codis 集群方案

 3 years ago
source link: https://www.lbbniu.com/8800.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

VNrEZrB.gif

随着公司项目的发展,单台redis的性能逐渐达到瓶颈,为了保证业务的正常运行,必须对单台redis进行扩展,组建redis的集群。在这次集群组建的过程中我们采用了豌豆荚开源的codis集群来承接业务需求,通过再开多个实例的方式来分担redis的业务压力。具体的codis集群搭建的过程就不在此赘述,本文主要记录线上redis数据迁移到codis中的过程。

在迁移数据前,我们对redis中现有数据量做了统计,其aof持久化文件大小达到22G左右(新重写的aof文件大小)。在迁移前我们准备了三种方案来完成数据迁移工作:

「第一种」是停止线上业务,对redis数据完全持久化后再使用持久化文件做数据的导入工作。此种方式是最为稳妥也最简单的导入方式,但是缺点在于必须停止线上业务进行操作,数据持久化和导入期间不允许线上业务对Redis进行操作,停服务时间包括持久化时间,数据导入时间,预估时间在30-60分钟。因为会停服时间过长,此方案最终被放弃。

「第二种」是通过Redis数据迁移工具来完成迁移操作,现在市面上主要的迁移工具有codis官方提供的迁移工具redis-port以及唯品会开源的redis-migrate-tool,这两个工具在原理上都是一样的,模拟一个redis的slave,然后从源redis中同步数据到新的集群,这两种工具都支持数据的热同步,可以不停线上服务的同时同步数据,然后做一次闪断将业务切换到新的集群就可以了。但是这两个工具都有一些不支持的redis命令,比如redis-migrate-tool不支持RPOPLPUSH命令,而且对于不支持的命令其会直接丢弃,并不会修改数据(我也是醉了,写操作命令不支持,居然敢说支持热同步,谁给的唯品会勇气)。所以这种方案最终也被放弃。

「第三种」是通过利用reids的appendonly文件来导入数据,由于redis采用aof的方式持久化时会把所有的操作按时间记录到持久化文件中,这就意味着如果我们能记录下在某个时间点这个文件内容的,然后就可以进行增量的备份,导入等操作,但是如何记录某个时间点上这个文件的内容呢?其实很简单,我们可以手动对redis进行aof文件的重写,然后利用redis info信息中aof_base_size和aof_current_size这两个值来做增量数据的导入就可以了。其中我们还需要利用head和tail命令的两个功能,就是按字节截取文件内容,具体的方案如下:

1、关闭自动重写aof,避免在我们操作appendonly文件时redis自动重写,从而导致我们记录的字节点发生变化。

127.0.0.1:6379> CONFIG SET auto-aof-rewrite-percentage 0

2、手动执行自动重写操作,创建一份完整的appendonly.aof文件,这可以提高我们数据导入的速度,待执行完成后,我们要获取一下当前的 aof_base_size 值,使用这个值来导入数据到codis。

127.0.0.1:6379> BGREWRITEAOF    #开始重写aof文件
127.0.0.1:6379> info
……
aof_enabled:1
aof_rewrite_in_progress:0        #当前是否有重写进程在执行,1表示正在重写aof,0表示当前没有重写操作
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:417    #上次重写操作使用的时间,单位是秒
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok     #上次重写操作的执行结果,ok表示正常
aof_last_write_status:ok
aof_current_size:26501437420     #aof文件当前的字节数,做增量数据导入是会用到
aof_base_size:22704815550        #aof文件重写完成时的字节数
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:57
……

此时我们可以看到,aof_base_size这个参数的值就是redis在执行完一次完整的aof文件重写后那一时刻的aof文件的字节数,aof_current_size这个参数的值就是从aof重写完成时间点到当前时间点的aof文件的字节数,其中两者的差值就是这段时间的增量数据,利用这个字节数就可以做增量数据的导入了。

3、导入重写完成时的redis数据,通过head命令截取了appendonly.aof文件的前22704815550个字节,导入codis中

head -c 22704815550 /var/lib/redis/6379/appendonly.aof | redis-cli -h codis地址 -p codis端口 --pipe

4、停止业务,禁用源redis端口,保证在切换过程中没有新的redis操作进行,此时可以通过iptables封掉redis端口的方式,或者直接停止redis服务来控制,本文采用iptables的方式来封锁端口。

5、确保没有新的redis操作后,我们查看info信息中当前 aof_current_size 参数的值,准备做增量数据的导入。利用tail命令和aof_current_size – aof_base_size的差值来进行增量数据的导入。

tail -c 3796621870 /var/lib/redis/6379/appendonly.aof | redis-cli -h codis地址 -p codis端口 --pipe

6、修改业务代码中redis的地址到codis的地址,启动服务,此时原redis的访问端口依然被封闭,待服务正常后就可以关闭原redis服务了。

至此,reids中的数据已经完全导入到新的codis集群中了。在本方案中,线上业务需要停止服务,但是停服时间已经得到了大幅度的减少。在第一次导入数据时aof文件有22G,耗时大概10分钟左右,但此时线上的业务并没有停止,在第二次导入增量数据的时候,经过实测1G左右的增量数据导入时间大概在1分钟左右,加上封端口等操作,基本可以控制在5分钟内完成。上述步骤还可以通过脚本来完成,可以进一步缩减停服时间到两分钟之内,这个时间对于公司当前的场景是可以接受的。

v6jieyu.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK