redis迁移工具

我的文章会先发布到个人博客后,再更新到简书,可以到个人博客或者gzh获取更多内容。


背景

当我们需要面对数据迁移(部分数据导出导入、redis集群迁移、云上redis与云下redis之间迁移)、架构变更(单点到集群、m分片到n分片)、redis版本升级或者异地多活容灾等情况时,我们就需要将redis单点或集群中的数据迁移到另一个redis集群或实例中。

迁移工具

redis自带的dump与restore

redis-cli -h localhost -a passwd -n 0 keys "*" | while read key
do
  redis-cli -h localhost -a passwd -n 0 --raw dump $key | perl -pe 'chomp if eof' | redis-cli -h localhost -a passwd -n 12 -x restore $key 0
done

缺点:每次只能处理单个key,大量数据迁移和集群相关需要写复杂脚本或程序

redis-cli后续新增的集群操作

手动备份集群数据

#redis-cli --cluster backup host:port backup_directory
redis-cli --cluster backup 192.168.60.200:6101 ./
ls -a
#.   nodes.json                                                                   redis-node-192.168.60.200-6102-c91ee22d2a365dc0db65385f0d4f81c39b2690f7.rdb
#..  redis-node-192.168.60.200-6101-52cf8d763cc554a20126488beaf2c03febfd490f.rdb  redis-node-192.168.60.200-6103-b0e053f116dd121bfe23ca7464608b2584f42328.rdb
#会生成节点相关信息和对应节点的rdb文件

import 迁移

#import   host:port --cluster-from host:port [--cluster-copy | --cluster-replace]
#从一个redis单例192.168.60.200:6101导入到192.168.60.200:6104所在集群
redis-cli --cluster import 192.168.60.200:6104 --cluster-from  192.168.60.200:6101 --cluster-copy

缺点:导出redis节点不能是集群的节点只能是非集群

redis-dump redis-load

redis-dump -u 127.0.0.1:6378 -a password > redis_6378.json
cat redis_6378.json redis-load -u 127.0.0.1 -a password

缺点:只能单点到单点或同节点数量和槽分布一样的集群间数据迁移,且会用到keys命令,迁移数据过大会卡住redis其他服务。

redis-migrate-tool

唯品会开源的redis迁移工具,快速、多线程、基于redis复制、实时迁移、迁移过程中,源集群不影响对外提供服务、异构迁移、过滤功能、迁移状态显示、完善的数据抽样校验。

迁移源: 单独的redis实例,twemproxy集群,redis cluster,rdb文件,aof文件。
目标: 单独的redis实例,twemproxy集群,redis cluster,rdb文件。

github地址

官方版本: 仅支持redis3及以下版本
其他人优化版本 :基于官方版本修改,支持redis4及以上版本

官方文档

文档地址

例子

配置

配置文件示例:从redis cluster集群迁移数据到另外一个cluster集群

#cat rmt.conf

[source]
type: redis cluster
servers:
 - 127.0.0.1:8379
[target]
type: redis cluster
servers:
 - 127.0.0.1:7379
[common]
listen: 0.0.0.0:8888

配置文件示例:从 rdb 文件恢复数据到 redis cluster 集群

#cat rmt.conf
[source]
type: rdb file
servers:
 - /data/redis/dump1.rdb
 - /data/redis/dump2.rdb
 - /data/redis/dump3.rdb

[target]
type: redis cluster
servers:
 - 127.0.0.1:7379

[common]
listen: 0.0.0.0:8888

运行

redis-migrate-tool -c rmt.conf -o log -d

运行状态

通过redis-cli连接redis-migrate-tool监控的端口,运行info命令

redis-cli -h 127.0.0.1 -p 8888
127.0.0.1:8888> info
# Server
version:0.1.0
os:Linux 2.6.32-573.12.1.el6.x86_64 x86_64
multiplexing_api:epoll
gcc_version:4.4.7
process_id:9199
tcp_port:8888
uptime_in_seconds:1662
uptime_in_days:0
config_file:/ect/rmt.conf
# Clients
connected_clients:1
max_clients_limit:100
total_connections_received:3
# Memory
mem_allocator:jemalloc-4.0.4
# Group
source_nodes_count:32
target_nodes_count:48
# Stats
all_rdb_received:1
all_rdb_parsed:1
all_aof_loaded:0
rdb_received_count:32
rdb_parsed_count:32
aof_loaded_count:0
total_msgs_recv:7753587
total_msgs_sent:7753587
total_net_input_bytes:234636318
total_net_output_bytes:255384129
total_net_input_bytes_human:223.77M
total_net_output_bytes_human:243.55M
total_mbufs_inqueue:0
total_msgs_outqueue:0

数据校验

数据校验默认是1000个,可以更改调大

redis-migrate-tool -c rmt.conf -o log -C redis_check
Check job is running...
Checked keys: 1000
Inconsistent value keys: 0
Inconsistent expire keys : 0
Other check error keys: 0
Checked OK keys: 1000
All keys checked OK!
Check job finished, used 1.041s

优点:完全满足redis集群迁移的所有需要,使用简单。
缺点:官方版本不支持redis4及以上的redis版本,优化版不知道稳定性如何,遇到问题查找困难。

redis-shake

能做什么.png

redis-shake是阿里云基于豌豆荚redis-port开发的一款非常好用的工具,可以支持备份、恢复、解析、同步等功能,主要的功能有:

  • decode,对RDB文件进行读取,并以json格式存储
  • restore,将RDB文件恢复到目的Redis服务器
  • dump,将源Redis服务器的数据通过RDB文件的方式保存下来
  • sync,支持源Redis和目的Redis的数据同步,通过模拟成Slave(使用psync),支持全量和增量数据的同步,对单节点、主从、集群环境之间进行同步(2.8-5.0版本,codis环境),也支持云上环境
  • rump,使用scan和restore命令进行数据迁移,对不支持psync命令的环境可以使用这种方式,仅支持全量的数据迁移
原理.png

github地址
下载地址
文档

迁移方式

sync/psync方式

例子:单点到集群迁移

#修改sync.toml

type = "sync"
[source]
address = "192.168.0.2:6379"
password = "r-aaaaa:xxxxx"

[target]
type = "cluster"
address = "192.168.0.1:6379" # 这里写集群中的任意一个节点的地址即可
password = "r-ccccc:xxxxx"

#启动 redis-shake:
./redis-shake sync.toml

source:为一个单点或者集群的某个节点(集群迁移,每个主节点需要对应启动一个redis-shake)
type: standalone 或 cluster,分别对应目标redis是单机或集群情况

集群与集群间迁移,可以利用官方自带cluster_helper.py自动启动源集群所有分片的数据迁移。

该方式不仅能应用与数据迁移或redis版本升级,还能通过该方法实现异地多活、容灾备份

dump方式

#修改 restore.toml
type = "restore"

[source]
rdb_file_path = "/path/dump.rdb"

[target]
type = "standalone" #恢复到单点
#type = "cluster" #恢复到集群
address = "127.0.0.1:6379"
password = "r-aaaaa:xxxxx"

scan方式

云厂商出于种种考虑禁用了 Redis 的 PSync 命令时,psync不可用。 对于这种情况可以使用 redis-shake 的 scan 模式来进行数据迁移,原理是调用 scan 命令来获取 Redis 中的 key,然后使用 dump 命令获取 key 的内容,最终使用 restore 命令恢复 key 至目的端。
scan命令的缺点就是会漏key,key的一致性不能保证,且该方式没有同步增量的功能,所以推荐以上两种。

type = "scan"

[source]
address = "r-aaaaa.redis.zhangbei.rds.aliyuncs.com:6379"
password = "r-aaaaa:xxxxx"

[target]
type = "standalone" #恢复到单点
#type = "cluster" #恢复到集群
address = "192.168.0.1:6379" # 这里写单点的地址或集群中的任意一个节点的地址即可
password = "r-ccccc:xxxxx"

集群同步到集群与 sync/psync类似,通过cluster_helper.py 启动同步

filters 做数据清洗

redis-shake支持同步过程中做数据筛选

--- cat filters/print.lua
--- function name must be `filter`
---
--- arguments:
--- @id number: the sequence of the cmd
--- @is_base boolean: whether the command is decoded from dump.rdb file
--- @group string: the group of cmd
--- @cmd_name string: cmd name
--- @keys table: keys of the command
--- @slots table: slots of the command
--- @db_id: database id
--- @timestamp_ms number: timestamp in milliseconds, 0 if not available

--- return:
--- @code number:
--- * 0: allow
--- * 1: disallow
--- * 2: error occurred
--- @db_id number: redirection database id

function filter(id, is_base, group, cmd_name, keys, slots, db_id, timestamp_ms)
    print(string.format("lua filter. id=[%d], is_base=[%s], db_id=[%d], group=[%s], cmd_name=[%s], keys=[%s], slots=[%s], timestamp_ms=[%d]",
          id, tostring(is_base), db_id, group, cmd_name, table.concat(keys, ", "), table.concat(slots, ", "), timestamp_ms))
    return 0, db_id
end

code:可选值 0,1,2

  • 0:允许此条数据发送至对端
  • 1:跳过此条数据
  • 2:不应该出现此数据,立即终止 redis-shake

db_id:代表这条命令会发送到哪个 database,只在 swap.db 中使用。一般情况下与传入 db_id 保持一致即可。

优点;稳定,使用的人多,版本还在更新维护,redis各种版本都支持,功能丰富
缺点:集群与集群间同步迁移等操作需要借助python脚本,当源集群分片节点过多,会开启对应数量的进程,会对运行机器有一定的性能要求。

迁移后的数据检验

redis-full-check

同样是阿里的开源项目, redis-full-check通过全量对比源端和目的端的redis中的数据的方式来进行数据校验,其比较方式通过多轮次比较:每次都会抓取源和目的端的数据进行差异化比较,记录不一致的数据进入下轮对比(记录在sqlite3 db中)。然后通过多伦比较不断收敛,减少因数据增量同步导致的源库和目的库的数据不一致。最后sqlite中存在的数据就是最终的差异结果。
github地址

例如:源redis库是10.1.1.1:1234,目的库是10.2.2.2:5678:

./redis-full-check -s 10.1.1.1:1234 -t 10.2.2.2:5678 -p mock_source_password -a mock_target_password --metric metric --log log --result result

#metric 文件信息
type Metric struct {
    DateTime     string       `json:"datetime"`      // 时间 格式: 2018-01-09T15:30:03Z
    Timestamp    int64        `json:"timestamp"`     // unix秒级时间戳
    Id           string       `json:"id"`            // run id
    CompareTimes int          `json:"comparetimes"`  // 对比轮次
    Db           int32        `json:"db"`            // db id
    DbKeys       int64        `json:"dbkeys"`        // db里的总key数
    Process      int64        `json:"process"`       // 进度, 百分比
    OneCompareFinished bool                               `json:"has_finished"` // 本次compare是否完成
    AllFinished        bool                               `json:"all_finished"` // 全部compare是否完成
    KeyScan      *CounterStat `json:"key_scan"`      // scan key的数量
    TotalConflict      int64  `json:"total_conflict"` // conflict的总数, 包含key + field
    TotalKeyConflict   int64                              `json:"total_key_conflict"`  // key conflict总数
    TotalFieldConflict int64                              `json:"total_field_conflict"` // field conflict总数
    // 以下两个map第一层key是字段类型, 有string, hash, list, set, zset, 第二层key是冲突类型, 有有type(类型冲突) / value(值冲突) / lack source(源端缺失) / lack target(目标端缺失) / equal(无冲突)
    KeyMetric    map[string]map[string]*CounterStat `json:"key_stat"`  // key metric
    FieldMetric  map[string]map[string]*CounterStat `json:"field_stat"`  // field metric
}

type CounterStat struct {
    Total int64 `json:"total"` // 总量
    Speed int64 `json:"speed"` // 速度
}

redis-rdb-tools

Rdbtools(https://github.com/sripathikrishnan/redis-rdb-tools)是 Redis 的 dump.rdb 文件的解析器。
可以将dump.rdb文件解析成方便比对的文件直接进行文件对比
source_dump.rdb target_dump.rdb

rdb --command diff source_dump.rdb | sort > dump1
rdb --command diff target_dump.rdb | sort > dump2
kdiff3 dump1 dump2 #运行你最喜欢的 diff 程序 或小文件直接vimdiff

参考资料

RedisMigrateTool 文档
RedisShake Wiki

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容