娃哈哈好喝-真的!
技术够用就行,吃好喝好睡好!

redis集群数据迁移

1、环境介绍

redis集群A:
172.20.20.164:6379
172.20.20.165:6379
172.20.20.166:6379
密码:Aa123456

redis集群B:
172.20.20.231:6379
172.20.20.231:6379
172.20.20.231:6379
密码:Aa123456

需求将集群A同步到集群B

2、工具配置

借助阿里开源的工具redis-shake,git地址:

https://github.com/tair-opensource/RedisShake

支持多种模式,比如单机->单机,单机->集群,集群->集群

如果是单机->单机模式,配置文件类似如下,修改sync.toml文件

[source]
address = "172.20.20.2164:6379"
password = "Aa123456"

[target]
type = "standalone"
address = "172.20.20.231:6379"
password = "Aa123456"

启动

./redis-shake sync.toml

单机->集群模式

[source]
address = "172.20.20.2164:6379"
password = "Aa123456"

[target]
type = "cluster"
address = "172.20.20.231:6379"
password = "Aa123456"

启动

./redis-shake sync.toml

集群->集群

type = "sync"
[source]
version = 6.2 # redis version, such as 2.8, 4.0, 5.0, 6.0, 6.2, 7.0, ...
address = "172.20.20.164:6379"
password = "Aa123456"
tls = false

[target]
type = "cluster" # "standalone" or "cluster"
version = 6.2 # redis version, such as 2.8, 4.0, 5.0, 6.0, 6.2, 7.0, ...
address = "172.20.20.231:6379"
password = "Aa123456"

方法一:

因为集群是3节点,所以需要启动三个redis-shake进程来分别同步三个节点,三个节点可以当作三个单机节点,但是每个redis-shake进程不能在同一个目录下启动,因为会有临时文件产生,同一个目录下临时文件会有冲突,这种方式比较繁琐,不再演示

方法二:

借助cluster_helper.py工具,通过脚本cluster_helper.py可以很方便的启动多个redis-shake进程从集群各节点同时迁移

需要python3.6及以上版本,安装依赖

cd RedisShake/cluster_helper
pip3 install -r requirements.txt

开始迁移

cd RedisShake/cluster_helper
python3 cluster_helper.py ../redis-shake ../sync.toml

哨兵模式

同步方法可以看作单机->单机的模式,忽略哨兵功能

3、检测同步结果

同样借助阿里的开源工具,同一个项目下的工具:redis-full-check

https://github.com/tair-opensource/RedisFullCheck

下载解压后就是这几个文件,有不同系统版本

[root@datacenter01 redis-full-check]# ls
ChangeLog redis-full-check.darwin redis-full-check.linux redis-full-check.windows
[root@datacenter01 redis-full-check]#

参数说明

	-s, --source=SOURCE               源redis库地址(ip:port),如果是集群版,那么需要以分号(;)分割不同的db,只需要配置主或者从的其中之一。例如:10.1.1.1:1000;10.2.2.2:2000;10.3.3.3:3000。
-p, --sourcepassword=Password 源redis库密码
--sourceauthtype=AUTH-TYPE 源库管理权限,开源reids下此参数无用。
--sourcedbtype= 源库的类别,0:db(standalone单节点、主从),1: cluster(集群版),2: 阿里云
--sourcedbfilterlist= 源库需要抓取的逻辑db白名单,以分号(;)分割,例如:0;5;15表示db0,db5和db15都会被抓取
-t, --target=TARGET 目的redis库地址(ip:port)
-a, --targetpassword=Password 目的redis库密码
--targetauthtype=AUTH-TYPE 目的库管理权限,开源reids下此参数无用。
--targetdbtype= 参考sourcedbtype
--targetdbfilterlist= 参考sourcedbfilterlist
-d, --db=Sqlite3-DB-FILE 对于差异的key存储的sqlite3 db的位置,默认result.db
--comparetimes=COUNT 比较轮数
-m, --comparemode= 比较模式,1表示全量比较,2表示只对比value的长度,3只对比key是否存在,4全量比较的情况下,忽略大key的比较
--id= 用于打metric
--jobid= 用于打metric
--taskid= 用于打metric
-q, --qps= qps限速阈值
--interval=Second 每轮之间的时间间隔
--batchcount=COUNT 批量聚合的数量
--parallel=COUNT 比较的并发协程数,默认5
--log=FILE log文件
--result=FILE 不一致结果记录到result文件中,格式:'db diff-type key field'
--metric metric文件
--bigkeythreshold=COUNT 大key拆分的阈值,用于comparemode=4
-f, --filterlist=FILTER 需要比较的key列表,以分号(;)分割。例如:"abc*|efg|m*"表示对比'abc', 'abc1', 'efg', 'm', 'mxyz',不对比'efgh', 'p'。
-v, --version

说用说明

例如:源redis库是172.20.20.164:6379,目的库是172.20.20.231:6379:
./redis-full-check -s 172.20.20.164:6379 -t 172.20.20.231:6379 -p Aa123456 -a Aa123456 --metric --log log --result result

比较原理

对比模式(comparemode)有三种可选:

KeyOutline:只对比key值是否相等。
ValueOutline:只对比value值的长度是否相等。
FullValue:对比key值、value长度、value值是否相等。
  对比会进行comparetimes轮(默认comparetimes=3)比较:

第一轮,首先找出在源库上所有的key,然后分别从源库和目的库抓取进行比较。
第二轮开始迭代比较,只比较上一轮结束后仍然不一致的key和field。

对于key不一致的情况,包括lack_source ,lack_target 和type,从源库和目的库重新取key、value进行比较。
value不一致的string,重新比较key:从源和目的取key、value比较。
value不一致的hash、set和zset,只重新比较不一致的field,之前已经比较且相同的filed不再比较。这是为了防止对于大key情况下,如果更新频繁,将会导致校验永远不通过的情况。
value不一致的list,重新比较key:从源和目的取key、value比较。
每轮之间会停止一定的时间(Interval)。
  对于hash,set,zset,list大key处理采用以下方式:

len <= 5192,直接取全量field、value进行比较,使用如下命令:hgetall,smembers,zrange 0 -1 withscores,lrange 0 -1。
len > 5192,使用hscan,sscan,zscan,lrange分批取field和value。

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"` // 速度
}

sqlite 3 db文件

结果会保存在sqlite3 db file中,不指定的话,就是当前目录的 result.db 文件:比如有3轮比较,那么会有result.db.1,result.db.2,result.db.33个文件,

表key:保存不一致的key
表field:保存hash,set,zset,list不一致的field, list 存的是下标值
表feild的key_id字段关联表key的id字段
表key_<N>和field_<N>:保存第N轮比较后的结果,即中间结果。

使用举例:

$ sqlite3  result.db

sqlite> select * from key;
id         key             type       conflict_type db         source_len target_len
----------  ---------------  ----------  -------------  ----------  ----------  ----------
1           keydiff1_string string     value          1           6           6
2           keydiff_hash     hash       value          0           2           1
3           keydiff_string   string     value          0           6           6
4           key_string_diff string     value          0           6           6
5           keylack_string   string     lack_target    0           6           0
sqlite>

sqlite> select * from field;
id         field       conflict_type key_id
----------  ----------  -------------  ----------
1           k1         lack_source    2
2           k2         value          2
3           k3         lack_target    2
赞(0)
未经允许不得转载:娃哈哈好喝 » redis集群数据迁移
分享到: 更多 (0)