到今天为时2周的迁移工作算是完成了,在这里做下总结、复盘。

一、迁移背景
1、线上8台32G的机器内存,采用allkeys-lru的淘汰策略,主要的数据类型是string且无任何的过期时间。每台机器是2.4-3.2亿不等。
2、运维给了32台机器,每台机器最大内容10G,需要把20亿数据分打散到32台上。
二、迁移方案
首先,线上开启双写,把新数据同步到新旧redis机器上。
其次,定迁移方案。
方案一、dump出来rdb文件到各个机器上,载入恢复,很明显新机器最大内存限制无法满足dump要求
方案二、程序迁移,采用scan扫描出每台机器上的key,再通过key找到对应的value。
通过背景可以知道,只能选用方案二。
三、问题考虑
1、scan是否会丢数据
很肯定的说,scan不会丢任何的数据,但可能会重复key,这个主要由于缩容导致的,具体可以问下度娘或者看下redis的rehash那块的源码。
2、scan是否很消耗性能
scan扫描的是字典中存在key,这些key都是hash在一个桶上,每次scan后,会返回下一次的游标,因此不会是否消耗性能与你每次扫描的条数有相当大的关系。每次取多少条数需要根据你的业务及运行情况取值。
3、程序执行中崩溃怎么办?
这需要你的程序记录当前执行的游标。
4、那种语言实现
这种迁移java、php、go都可以,我使用go+redigo作为实现方案,充分的利用了goroutine和channel。
5、对比迁移前后数据信息
在执行迁移任务的时候先把新旧机器的info信息打到日志中,结束后的信息也要打印到日志中直接对比即可。
四、具体思路
1、一个scan协程,每次扫描200条,把key从redis中扫描出来,然后扔到read管道中。
2、15个read协程,读取管道中的key,通过pipeline+dump(dump是个命令)的方式使用命令把数据取出,
再对进行分组,扔到write管道中。
3、20个协程读取write管道数据,把数据通过hash算法再次对key进行分组通过pipleline+restore(restore是个命令)的方式写入对应的机器中。
4、8台机器全部执行完毕后,再开启检测keys是否已经存在的方法,补充写入失败的数据。
五、迁移时常及遇到的问题
1、每次扫描200条,2.4亿数据40分钟可以迁移完毕,单进程cpu使用率到370%,带宽平均是120Mb,
如果无法接收这两个指标,可以把200条调小。
2、重点说下遇到的问题
迁移完成后,发现旧机器比新机器多3000万条数据,通过exists key检测完后,仍然少3000万条,通过down出来一台较少的机器上所有的key进行对比,发现有重复的key,也就是说一个key在两台机器上。大概率是之前,对机器直接进行了扩容而未迁移数据所导致。
3、数据检测
scan新机器上的key,从每次取的条数中,随机挑选几条到旧机器上查找对比。
4、日志问题
因为迁移的数据较大,所以日志方面程序调试时要全,真正执行后,尽量要少,否则一台机器下来要用到2G左右的日志太大了。

至此迁移完毕了,如果有需要代码参考的可以留言。