• Redis开发与运维:数据迁移


    问题

    最近项目重构,提前想把一台上的redis实例转移到另一台redis实例上。

    源redis数据库:阿里云Redis、VPC网络、Server版本2.8.19
    
    目标数据库:阿里云Redis、VPC网络、Server版本4.0.11
    

    前提:

    当前我们使用Redis作为我们的数据库(永久+ 临时缓存)
    

    目标:

    把当前永久性数据导入到目标数据库,临时缓存数据不做处理
    

    方案

    设置主从复制,这个应该是比较稳妥的方案,但是支持主从必须3.0以上  -- 这个方案否掉了
    
    那就使用键迁移命令,查了一下三种方式:move 、dump + restore 、migrate
    

    自测

    Windows服务器,下载了源数据库 redis2.8.19
    
    分别启用了两个实例分别是 6999和7999
    
    源数据 6999,目标数据 7999
    

    move

    这个命令是做实例内,db迁移的,对于当前实例间同步是不满足的。

    但也不妨尝试一下:

    db5中的键移到db6,

    localhost:6999[5]> get QianBiTou:VC:Config
    "0x001,1,2,3"
    localhost:6999[5]> move  QianBiTou:VC:Config 6
    (integer) 1
    localhost:6999[5]> get QianBiTou:VC:Config
    (nil)
    
    

    移动嘛所以db5的键就没了,db6才能获取到

    localhost:6999[5]> SELECT 6
    OK
    localhost:6999[6]> get QianBiTou:VC:Config
    "0x001,1,2,3"
    

    dump + restore

    1、源数据库上:dump 相当于把这个键按照协议序列化

    localhost:6999[6]> get QianBiTou:VC:Config
    "0x001,1,2,3"
    localhost:6999[6]> DUMP  QianBiTou:VC:Config
    "x00x0b0x001,1,2,3x06x00xfbx06ZUnxdexb5x95"
    
    

    2、目标数据库上:restore 进行初始化这个键

    127.0.0.1:7999[2]> RESTORE QianBiTou:VC:Config 0 "x00x0b0x001,1,2,3x06x00xfbx06ZUnxdexb5x95"
    OK
    127.0.0.1:7999[2]> GET QianBiTou:VC:Config
    "0x001,1,2,3"
    

    这个方案呢,可行但是看了一下第三个,感觉第3个是2的改进版本

    migrate

    localhost:6999[6]> help migrate
    
      MIGRATE host port key destination-db timeout [COPY] [REPLACE]
      summary: Atomically transfer a key from a Redis instance to another one.
      since: 2.6.0
      group: generic
    
    

    从这到那:127.0.0.1:6999 -> 127.0.0.1:7999 key=QianBiTou:VC:Config

    1、看看源数据库6999,db6这个key的值。嗯,有值。

    localhost:6999[6]> get QianBiTou:VC:Config
    "0x001,1,2,3"
    

    2.、再看看目标数据库,把这个key清场.

    127.0.0.1:7999[2]> GET QianBiTou:VC:Config
    "0x001,1,2,3"
    127.0.0.1:7999[2]> DEL QianBiTou:VC:Config
    (integer) 1
    127.0.0.1:7999[2]> GET QianBiTou:VC:Config
    (nil)
    
    

    3.、准备好了,那就开始转吧,走你

    localhost:6999[6]> get QianBiTou:VC:Config
    "0x001,1,2,3"
    localhost:6999[6]>  MIGRATE 127.0.0.1 7999 QianBiTou:VC:Config 2 5000
    OK
    

    4、看看目标机器上过来了木有

    en, 过来了
    
    127.0.0.1:7999[2]> GET QianBiTou:VC:Config
    "0x001,1,2,3"
    

    5.、再看看源数据库

    e...没啦?
    
    localhost:6999[6]> get QianBiTou:VC:Config
    (nil)
    

    再进一步

    查阅资料发现,MIGRATE  = dump + restore + del ,因为它是原子性的所以推荐使用这个方法。
    
    但是会把原来的数据删掉,类似于跨实例move。文档中 加上copy和replace 参数就不会删除源数据了。
    
    • copy 复制

    • replcae 复制并替换

    1.、再试试,数据重新加回去

    localhost:6999[6]> set QianBiTou:VC:Config 0x001,1,2,3
    OK
    
    localhost:6999[6]>  MIGRATE 127.0.0.1 7999 QianBiTou:VC:Config 2 5000 replace
    (error) ERR wrong number of arguments for 'migrate' command
    

    2.、报错了,再查查官方资料。好吧,还是版本不支持:

        COPY and REPLACE are available only in 3.0 and above. KEYS is available starting with Redis 3.0.6. AUTH is available starting with Redis 4.0.7.
    

    最终方案

    1、主从 --不行,版本低了

    2、MOVE-- 不行,实例内,数据没了

    3、 MIGRATE --不行,实例间,版本不行+数据没了

    4、 dump + restore 这个算是最终方案

    方案可行性:因为不涉及缓存数据,是永久数据的导出导入,所以不存在原子性问题,还有忘记了一点数据量非常小
    

    执行方案

           [TestMethod]
            public async Task RestoreToOtherRedis_Test()
            {
                // 源redis
                string sourceRedis = "r-xxxxxxxxxxxpd.redis.rds.aliyuncs.com:6379,password=uuuuuu,defaultDatabase=5,prefix=";
    
                //目标redis
                string targetRedis = "r-xxxxxxxxxxxxpd.redis.rds.aliyuncs.com:6379,password=uuuuuu,defaultDatabase=5,prefix=";
    
                List<string> keys = new List<string>();
                try
                {
                    using (var sourceClient = new CSRedis.CSRedisClient(sourceRedis))
                    {
                        // key 很少的时候使用cmd: keys *
                        // 建议使用 scan
                        keys = sourceClient.Keys("*").ToList();
                        using (var targetClient = new CSRedis.CSRedisClient(targetRedis))
                        {
    
                            foreach (var key in keys)
                            {
                                if (key.StartsWith("RedisCach"))
                                    continue;
    
                                // 序列化数据
                                var dump = sourceClient.Dump(key);
    
                                // 初始化数据
                                var ok = targetClient.Restore(key, dump);
    
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    string msg = ex.ToString();
                }
                finally
                {                
                }
    

    验证

    事后验证了一下,确实数据过来了
    

    注意点

    MOVE 实例内
    
    MIGRATE 原子操作。最好使用copy和replace 参数源数据不删除。
    
    DUMP  + RESTORE 不是原子操作
    

    补充同步工具:

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

    其实一开始的策略就是使用同步工具,但是考虑到实在不知所以然,就看了直接的redis同步。简单的命令就能解决问题。

    但是同步工具应该会有更多的应用场景和覆盖面积。

    redis-port  parse redis rdb file, sync data between redis master and slave  --主从同步工具
    

    工具简单,命令也不复杂。

    上一篇,有朋友留言redis-port,借此机会我尝试使用一下redis-port这个同步工具

    redis-port 已编译版

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

    cd 到解压目录

    redis-dump

    定义:持久化数据
    

    执行:$ ./redis-dump 127.0.0.1:6999 -o dd/dump.rdb

    验证

    $ ls -ls
    总用量 4
    4 -rw-r--r-- 1 sunchong sunchong 217 10月 21 17:36 dump.rdb
    
    

    redis-decode

        定义:dumped payload to human readable format (hex-encoding)【反序列化rdb,更加容易理解】
    

    Help:$ ./redis-decode --help

    
    Usage:
    	redis-decode [--ncpu=N] [--input=INPUT|INPUT] [--output=OUTPUT]
    	redis-decode  --version
    
    Options:
    	-n N, --ncpu=N                    Set runtime.GOMAXPROCS to N.
    	-i INPUT, --input=INPUT           Set input rdb encoded file.  [default: /dev/stdin].
    	-o OUTPUT, --output=OUTPUT        Set output file. [default: /dev/stdout].
    
    Examples:
    	$ redis-decode -i dump.rdb -o dump.log
    	$ redis-decode    dump.rdb -o dump.log
    	$ cat dump.rdb | redis-decode --ncpu=8 > dump.log
    
    

    执行:$ ./redis-decode -i dump.rdb -o stdout

    2019/10/21 15:42:40 decode.go:59: [INFO] decode: input = "dump.rdb", output = "stdout"
    2019/10/21 15:42:40 decode.go:110: [INFO] decode: (r,w,o) = (read,write,objects)
    2019/10/21 15:42:40 decode.go:135: [INFO] decode: file = 134 - [100.00%]   (r,w,o)=(134,114,2)   ~  (134,114,-)
    2019/10/21 15:42:40 decode.go:139: [INFO] decode: done
    
    

    验证:$ vim stdout

        {"db":0,"type":"list","key":"right","index":0,"value":"r1"}
        {"db":0,"type":"string","key":"QBT","value":"value1"}
    

    redis-restore

        从 6999 db0 dump.rdb 持久化到 7999 db0
        from 127.0.0.1:6999   to 127.0.0.1:7999
    

    执行:$ ./redis-restore -i dump.rdb -t 127.0.0.1:7999

    2019/10/21 17:05:39 restore.go:70: [INFO] restore: input = "dump.rdb", aoflog = "" target = "127.0.0.1:7999"
    2019/10/21 17:05:39 restore.go:126: [INFO] restore: (r,f,s/a,f,s) = (rdb,rdb.forward,rdb.skip/aof,rdb.forward,rdb.skip)
    2019/10/21 17:05:39 restore.go:155: [INFO] restore: size = 134 - [100.00%,  0.00%]   (r,f,s/a,f,s)=(134,0,2/0,0,0)   ~  (134,-,-/0,-,-)
    2019/10/21 17:05:39 restore.go:159: [INFO] restore: done
    
    

    验证:$ ./redis-restore -i dump.rdb -t 127.0.0.1:7999

    127.0.0.1:7999> KEYS *
    1) "right"
    2) "QBT"
    
    

    redis-sync

        定义:实例间实时同步
    

    执行:$ ./redis-sync 127.0.0.1:6999 -t 127.0.0.1:7999

    验证

    2019/10/21 17:41:16 sync.go:76: [INFO] sync: master = "127.0.0.1:6999", target = "127.0.0.1:7999"
    2019/10/21 17:41:16 sync.go:109: [INFO] sync: runid = "42d23b2a5d2a4fcce612854174bfc6db89d52cca", offset = 0
    2019/10/21 17:41:16 sync.go:111: [INFO] sync: rdb file = 217 (217)
    2019/10/21 17:41:16 sync.go:208: [INFO] sync: (r/f,s/f,s) = (read,rdb.forward,rdb.skip/rdb.forward,rdb.skip)
    2019/10/21 17:41:17 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(217/2,0/0,0)     ~  (217/-,-/-,-)     ~  speed=(217/2,0/0,0)   
    2019/10/21 17:41:18 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(217/2,0/0,0)     ~  (217/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:19 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(217/2,0/0,0)     ~  (217/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:20 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(14/0,0/1,0)
    2019/10/21 17:41:21 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:22 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:23 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:24 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:25 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:26 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:27 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:28 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:29 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(231/2,0/1,0)     ~  (231/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    2019/10/21 17:41:30 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(245/2,0/2,0)     ~  (245/-,-/-,-)     ~  speed=(14/0,0/1,0)
    2019/10/21 17:41:31 sync.go:250: [INFO] sync: rdb = 217 - [100.00%]   (r/f,s/f,s)=(245/2,0/2,0)     ~  (245/-,-/-,-)     ~  speed=(0/0,0/0,0) 
    

    源:127.0.0.1:6999

    127.0.0.1:6999> SET sc sc1
    OK
    127.0.0.1:6999> SET sc sc2
    OK
    127.0.0.1:6999> SET sc sc3
    OK
    127.0.0.1:6999> SET sc sc4
    OK
    127.0.0.1:6999> SET sc sc5
    OK
    127.0.0.1:6999> 
    
    

    目标:127.0.0.1:7999

    127.0.0.1:7999> get sc
    "sc5"
    127.0.0.1:7999> 
    
    
    总结
    
    工具对应的是 redis 4.X版本
    
    只是尝试了一下linux,windows下还没尝试,后续如有场景可以补充
    

  • 相关阅读:
    CentOS7 安装Docker最新稳定版
    C#采集解析log文件及CSV文件数据到DataTable
    RedHat/CentOS8使用Bash脚本查看Linux上的系统信息
    DataTable Select用法总结
    web开发
    minio 文件服务器
    在 Idea 中使用 Maven
    UGUI源码分析(零): 环境搭建
    高德地图的使用 vueamap+vue
    unity 模型 工作流
  • 原文地址:https://www.cnblogs.com/sunchong/p/11656285.html
Copyright © 2020-2023  润新知