Redis迁移工具redis-port使用&代码分析

2020-09-11 11:24:44 浏览数 (1)

Redis现在是互联网公司缓存的标配了,在一些场景下我们需要将redis的数据从一些实例迁移到其它实例上,一个好的Redis数据迁移工具可以起到事半功倍的效果,今天为大家介绍一款好用、稳定的工具:redis-port,我们在生产环境上有实际使用过。

源码地址:https://github.com/CodisLabs/redis-port

1、安装

先安装go,然后进入源代码的根目录,直接make就可以了;

我用的分支是redis-4.x-cgo。

2、使用

主要讲下迁移数据吧,redis-port有很多参数,这里只列一些常用参数:

-m:表示从哪里迁

-t:表示迁移到哪里去

./bin/redis-sync -m 172.21.106.228:6379 -t 172.21.106.228:9001

表示将数据从 172.21.106.228:6379 迁移到 172.21.106.228:9001

3、工作原理

讲工作原理之前,先了解下redis主、从同步的原理,因为redis-port的工作原理就是把自己模拟成一个从,利用主、从同步机制来完成数据迁移的。

在2.8之前redis主、从同步只有一种方式:sync

(图片来自 https://blog.csdn.net/sk199048/article/details/50725369 )

从服务器向主服务器发送sync命令,主服务器收到命令后,在后台用BGSAVE生成快照,然后将快照发送给从服务器。

另外主服务器生成RDB快照之后,将这个之后的写命令保存在一个缓冲区中,从服务器回放完命令后,主服务器将缓冲区的命令发送给从服务器。

这种方式在以下几个场景会有大的问题:

1、由于网络抖动从服务器暂时连不上主服务器,过了几秒后网络恢复了,这个期间其实只有很少的写操作,但也得全量同步,数据量比较小还好,如果量达到几十G了,这个时候主服务器基本上挂了;

2、一些从服务器因为升级、硬件等原因,需要暂时重启下,也得全量同步 ;

PSYNC1

sync的方式每次都全量同步,那能不能增量同步呢,PSYNC1就是为了解决这个问题而诞生的。

它的原理如下:

主服务器在运行时记录自己的运行ID,从服务器也会记录主服务器ID,如果因为网络抖动导致的主、从暂时断开,下次重连时,从服务器把主服务器 ID和偏移量等信息发送给主服务器,主服务器检查运行ID是否和自己相同,然后检查偏移量是否在复制缓冲区中,只要时间不断开太久,复制缓存冲不是太小,就可以进行增量同步了。

(PSYNC1只解决上面场景1的问题,Redis4.0推出的PSYNC2可以解决场景2下的问题)

再回到redis-port上,我们看下它的工作原理,先统一几个概念:

源服务器:表示要从哪个redis实例迁移数据

目标服务器:表示将数据迁到哪个实例上

工作原理如下:

1)、redis-port向源服务器发送PSYNC命令;

2)、源服务器将当前快照发送给redis-port;

3)、redis-port解析快照命令,发送给目标服务器;

4)、源服务器不断的将复制缓冲区的内容发送给Redis-port;

5)、redis-port将收到的复制缓区内容发送给目标服务器;

4、关键代码分析

发送psync命令

代码语言:javascript复制
var runid, offset, rdbSizeChan = redisSendPsyncFullsync(master.rd, master.wt)

解析RDB,发送给目标服务器;然后解析增量AOF日志:

代码语言:javascript复制
var jobs = NewParallelJob(flags.Parallel, func() {
   doRestoreDBEntry(entryChan, target.Addr, target.Auth,
      func(e *rdb.DBEntry) bool {
         if !acceptDB(e.DB) {
            master.rdb.skip.Incr()
            return false
         }
         master.rdb.forward.Incr()
         return true
      })
}).Then(func() {
//解析主服务器发送过来的Aof日志
AofdoRestoreAoflog(reader, target.Addr, target.Auth,
      func(db uint64, cmd string) bool {
         if !acceptDB(db) && cmd != "PING" {
            master.aof.skip.Incr()
            return false
         }
         master.aof.forward.Incr()
         return true
      })
}).Run()

如果有自定义需求,就可以从上面2处入手。

5、写在最后

使用redis-port迁移数据需要停机吗,答案是需要,因为在迁移数据的时候源服务器会不断的有写请求进来,等真正迁移完的时候停服才能保证数据一致,准备工作做的好的话,这个过程会很短。

0 人点赞