写点什么

【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(数据检查对比)

作者:洛神灬殇
  • 2023-01-10
    江苏
  • 本文字数:4093 字

    阅读完需:约 13 分钟

【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(数据检查对比)

redis-full-check 的使用背景

在经历了之前的文章内容章节内容,已完成 Redis 迁移后,可能会存在以下问题需要进行数据迁移之后的对比。例如,如果 Redis 迁移的过程出现异常,源端与目的端 Redis 的数据将会不一致。


  • 【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(在线同步数据)

  • 【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(离线同步数据)

  • 【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(scan 模式迁移)


在 Redis 迁移完成后进行数据校验可以检查数据的一致性,该如何校验就是我们本文的内容。我们在这里采用的是阿里开源的数据对比工具与 Redis-Shake 形成伴侣模式的开源工具 redis-full-check,使用 redis-full-check 进行校验能够找出异常数据,为数据对齐提供可靠依据,本文主要介绍如何使用 RedisFullCheck。


redis-full-check 的基本介绍

redis-full-check 是阿里云自研的 Redis 数据校验工具,能够提取源端和目的端的数据进行多轮差异化比较,并将比较结果记录在一个 SQLite3 数据库中,从而达到全量数据校验的目的。


迁移源端和目的端 Redis 实例需为主从版、单节点版、开源集群版以及部分云上带 proxy 的集群版(阿里云、腾讯云)。

开源地址

  • redis-full-check 源码地址: https://github.com/aliyun/redis-full-check



  • redis-full-check 下载地址: https://github.com/alibaba/RedisFullCheck/releases


编译源码

运行 ./bin/redis-full-check.darwin64 or redis-full-check.linux64,它分别在 OSX 和 Linux 中构建,然而,二进制文件并不总是最新版本。 或者您可以根据以下步骤构建 red- full-check 自己:


git clone https://github.com/alibaba/RedisFullCheck.gitcd RedisFullCheck/src/vendorGOPATH=`pwd`/../..; govendor sync 
复制代码


注意:必须先安装 govendor,然后拉出所有依赖


cd ../../ && ./build.sh
复制代码


执行 build.sh 进行编译即可。

基本原理

  • redis-full-check 通过全量对比源端目的端的 redis 中的数据的方式来进行数据校验,其比较方式通过多轮次比较:每次都会抓取源和目的端的数据进行差异化比较,记录不一致的数据进入下轮对比(记录在 sqlite3 db 中)。

  • 通过多伦比较不断收敛,减少因数据增量同步导致的源库和目的库的数据不一致。最后 sqlite 中存在的数据就是最终的差异结果。

数据对比介绍

redis-full-check 对比的方向是单向,如果希望对比双向,则需要对比 2 次,第一次以 A 为源库,B 为目的库,第二次以 B 为源库,A 为目的库。


  • 首次对别:会抓取源库 A 的数据,然后检测是否位于 B 中,反向不会检测,它检测的是源库是否是目的库的子集。每次比较,会先抓取比较的 key。


第一轮是从源库中进行抓取,后面轮次是从 sqlite3 db 中进行抓取;抓取 key 之后是分别抓取 key 对应的 field 和 value 进行对比,然后将存在差异的部分存入 sqlite3 db 中,用于下次比较

数据对比核心流程

下图是基本的数据流图。



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


  • KeyOutline:只对比 key 值是否相等。

  • ValueOutline:只对比 value 值的长度是否相等。

  • FullValue:对比 key 值、value 长度、value 值是否相等。


对比会进行 comparetimes 轮(默认 comparetimes=3)比较:


  • 第一轮,首先找出在源库上所有的 key,然后分别从源库和目的库抓取进行比较。

  • 第二轮,开始迭代比较,只比较上一轮结束后仍然不一致的 key 和 field。

不一致场景下分析

对于 key 不一致的情况,包括 lack_source ,lack_target 和 type,从源库和目的库重新取 key、value 进行比较。


  1. value 不一致的 string,重新比较 key:从源和目的取 key、value 比较。

  2. value 不一致的 hash、set 和 zset,只重新比较不一致的 field,之前已经比较且相同的 filed 不再比较。这是为了防止对于大 key 情况下,如果更新频繁,将会导致校验永远不通过的情况。

  3. 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。

使用 redis-full-check

  1. 解压 redis-full-check.tar.gz:tar -xvf redis-full-check.tar.gz

  2. 执行如下命令进行数据校验:


  • 单机实例之间进行数据对比检测


./redis-full-check -s $(source_redis_ip_port) -p $(source_password) -t $(target_redis_ip_port) -a $(target_password) 
复制代码


  • 集群实例之间进行数据对比检测


./redis-full-check -s "<Redis集群地址1连接地址:Redis集群地址1端口号;Redis集群地址2连接地址:Redis集群地址2端口号;Redis集群地址3连接地址:Redis集群地址3端口号>" -p <Redis集群密码> -t <Redis连接地址:Redis端口号> -a <Redis密码> --comparemode=1 --comparetimes=1 --qps=10 --batchcount=100 --sourcedbtype=1 --targetdbfilterlist=0
复制代码

参数信息介绍

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=FILE                 metric文件      --bigkeythreshold=COUNT       大key拆分的阈值,用于comparemode=4  -f, --filterlist=FILTER           需要比较的key列表,以竖线(|)分割。例如:"abc*|efg|m*"表示对比'abc', 'abc1', 'efg', 'm', 'mxyz',不对比'efgh', 'p'。  -v, --version
复制代码

对比实现案例

对比 2 个主从版/单节点:

./redis-full-check -t 10.101.72.137:30661 -s 10.101.72.137:30551
复制代码

对比主从和集群:

./redis-full-check -s "100.81.164.177:21331;100.81.164.177:21332;100.81.164.177:21333" -t 10.101.72.137:30551 --comparemode=1 --comparetimes=1 --qps=10 --batchcount=100 --sourcedbtype=1 --targetdbfilterlist=0
复制代码


由于集群版只有 db0,所以如果一端是集群版,另一端是非集群版(多个逻辑 db),则需要添加 sourcedbfilterlist 或者 targetdbfilterlist(非集群版本的一端)

查询对比结果

sqlite> select * from key;id          key              type        conflict_type  db          source_len  target_len----------  ---------------  ----------  -------------  ----------  ----------  ----------1           keydiff1_string  string      value          1           6           62           keydiff_hash     hash        value          0           2           13           keydiff_string   string      value          0           6           64           key_string_diff  string      value          0           6           65           keylack_string   string      lack_target    0           6           0sqlite>
sqlite> select * from field;id field conflict_type key_id---------- ---------- ------------- ----------1 k1 lack_source 22 k2 value 23 k3 lack_target 2
复制代码

对比结果差异分析

不一致类型

redis-full-check 判断不一致的方式主要分为 2 类:key 不一致和 value 不一致。

key 不一致

key 不一致主要分为以下几种情况:


  • lack_target : key 存在于源库,但不存在于目的库。

  • type: key 存在于源库和目的库,但是类型不一致。

  • value: key 存在于源库和目的库,且类型一致,但是 value 不一致。

  • value 不一致

不同数据类型有不同的对比标准:

  • string: value 不同。

  • hash: 存在 field,满足下面 3 个条件之一:

  • field 存在于源端,但不存在与目的端。

  • field 存在于目的端,但不存在与源端。

  • field 同时存在于源和目的端,但是 value 不同。

  • set/zset:与 hash 类似。

  • list: 与 hash 类似。


field 冲突类型有以下几种情况(只存在于 hash,set,zset,list 类型 key 中)


  • lack_source: field 存在于源端 key,field 不存在与目的端 key。

  • lack_target: field 不存在与源端 key,field 存在于目的端 key。

  • value: field 存在于源端 key 和目的端 key,但是 field 对应的 value 不同。

参考资料

发布于: 2023-01-10阅读数: 17
用户头像

洛神灬殇

关注

🏆 InfoQ写作平台-签约作者 🏆 2020-03-25 加入

【个人简介】酷爱计算机科学、醉心编程技术、喜爱健身运动、热衷悬疑推理的“极客达人” 【技术格言】任何足够先进的技术都与魔法无异 【技术范畴】Java领域、Spring生态、MySQL专项、微服务/分布式体系和算法设计等

评论

发布
暂无评论
【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(数据检查对比)_redis_洛神灬殇_InfoQ写作社区