問題
最近項目重構,提前想把一台上的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下還沒嘗試,后續如有場景可以補充