d96a23c8658f1e518cd45aa61b9f1304.png

一、介绍

redis-port是一款redis数据迁移工具,用来将数据从一个redis迁移到另一个redis实例/redis集群中 ,以下是官方地址:

https://github.com/CodisLabs/redis-port

使用也是非常的简单:

/redis-port sync -f 127.0.0.1:6379 -t 127.0.0.1:6380 -n 8

上述命令将127.0.0.1:6379这个redis实例的数据迁移到 127.0.0.1:6380 中。

我们在生产上迁移了多个redis集群的数据,运行非常稳定。

最近有这么一个场景:只迁移指定前缀的key,因为一个redis集群有好几个应用在用,如果全部都迁,时间太长,占的内存也比较大。

二、改造过程

我们先整理下redis-port的工作流程:

1、伪装一个从,向主redis 发起同步请求;

2、主redis将当前数据以rdb发送给redis-port;

3、redis-port解析rdb文件,然后1条1条的向目标redis写入数据;

4、接收主redis发送过来的增量命令,发往目标redis。

所以如果要改造的话,需要修改3和4两处,当然了还得增加参数解析的代码,具体步骤如下:

1、先修改cmd/flags.go 增加前缀的参数:

type Flags struct {   Source, Target string     //过滤前缀,即只迁移这个前缀的key  SourcePrefixs []string    AofPath string   TmpFile struct {     Path string     Size int64   }   ExpireOffset time.Duration }

其中SourcePrefixs为新加的字段,类型为一个字符串数组,因为前缀可能有多个。

2、修改cmd/flags.go解析参数函数parseFlagsFromArgs

 // 解析 sourcePrefix 前缀  for _, key := range []string{"--sourcePrefix"} {    var prefix string     if s, ok := d[key].(string); ok && s != "" {      prefix = s     }    //通过,分隔    flags.SourcePrefixs = strings.Split(prefix, ",")   }

3、修改cmd/libs.go,增加判断key是否包含指定前缀的函数

func strHasPrefix(key string, sourcePrefix []string)  bool{  if len(sourcePrefix) < 1 {    return  true  }  var hasPrefix bool  hasPrefix = false  for i := 0; i < len(sourcePrefix); i++{    if (strings.HasPrefix(key, sourcePrefix[i])) {      hasPrefix = true      break     }  }  return hasPrefix}

4、修改cmd/libs.go处理rdb文件的函数genRestoreCommands增加相应逻辑

//过滤非前缀的key  if (strHasPrefix(e.Key.String(), sourcePrefix) != true) {    log.Debug(e.Key.String() + " has no prefix: ignore it")    return  }

doRestoreDBEntry增加sourcePrefix参数

func doRestoreDBEntry(entryChan 

5、修改cmd/libs.go回放aof文件函数doRestoreAoflog

func doRestoreAoflog(reader *bufio2.Reader, targetPrefix string, sourcePrefix []string, addr, auth string, on func(db uint64, cmd string) bool) {//省略一些代码//如果前缀不为空,则判断是否为这个前缀    if (len(r.Array) > 1) {      var key= string(r.Array[1].Value)      if strHasPrefix(key, sourcePrefix) != true {        continue      }    }  //后续逻辑处理}

6、在入口cmd/sync.go增加参数声明

Options:   -n N, --ncpu=N                    Set runtime.GOMAXPROCS to N.   -m MASTER, --master=MASTER        The master redis instance ([auth@]host:port).   -t TARGET, --target=TARGET        The target redis instance ([auth@]host:port).  --sourcePrefix=SP            filter source key use prefix, separte with, .   --db=DB                           Accept db = DB, default is *.   --tmpfile=FILE                    Use FILE to as socket buffer.

再make编译下,可以试下效果:

开两个redis实例,实例A为6379端口,实例B为6380端口,实例A数据如下:

cbce776920173f9be9ed24602334ac20.png

执行redis-sync:

3873d7ce3aff5579c12c5f41e5a56303.png

看下实例B中的数据:

f82325f24e3f5a3184f9331e36041961.png

可以看到只有order前缀的数据才迁移过来了。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐