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
"\x00\x0b0x001,1,2,3\x06\x00\xfb\x06ZUn\xde\xb5\x95"

2、目標數據庫上:restore 進行初始化這個鍵

127.0.0.1:7999[2]> RESTORE QianBiTou:VC:Config 0 "\x00\x0b0x001,1,2,3\x06\x00\xfb\x06ZUn\xde\xb5\x95"
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下還沒嘗試,后續如有場景可以補充


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM