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

简介: 【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。

image.png



redis-full-check的基本介绍


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

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




开源地址


image.png

image.png



编译源码


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


git clone https://github.com/alibaba/RedisFullCheck.git
cd RedisFullCheck/src/vendor
GOPATH=`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中,用于下次比较



数据对比核心流程


下图是基本的数据流图。

image.png

对比模式(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比较。


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


  1. 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           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
复制代码


对比结果差异分析


不一致类型

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不同。




参考资料





相关文章
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
2070 0
分布式爬虫框架Scrapy-Redis实战指南
|
存储 NoSQL 数据库
Redis 逻辑数据库与集群模式详解
Redis 是高性能内存键值数据库,广泛用于缓存与实时数据处理。本文深入解析 Redis 逻辑数据库与集群模式:逻辑数据库提供16个独立存储空间,适合小规模隔离;集群模式通过分布式架构支持高并发和大数据量,但仅支持 database 0。文章对比两者特性,讲解配置与实践注意事项,并探讨持久化及性能优化策略,助你根据需求选择最佳方案。
1271 5
|
数据采集 存储 NoSQL
基于Scrapy-Redis的分布式景点数据爬取与热力图生成
基于Scrapy-Redis的分布式景点数据爬取与热力图生成
1159 67
|
12月前
|
存储 运维 NoSQL
Redis集群模式
Redis集群是一种分布式存储方案,旨在解决数据存储容量不足的问题。它通过将数据分片存储在多个节点上,实现数据的横向扩展。常见的分片算法包括哈希求余、一致性哈希和哈希槽分区。其中,Redis采用哈希槽分区算法,将数据均匀分配到16384个槽位中,每个分片负责一部分槽位。当节点故障时,集群通过故障检测和主从切换机制,确保服务的高可用性。集群还支持自动的数据迁移和负载均衡,保障系统稳定运行。
|
存储 缓存 NoSQL
告别数据僵尸!Redis实现自动清理过期键值对
在数据激增的时代,Redis如同内存管理的智能管家,支持键值对的自动过期功能,实现“数据保鲜”。通过`EXPIRE`设定生命倒计时、`TTL`查询剩余时间,结合惰性删除与定期清理策略,Redis高效维护内存秩序。本文以Python实战演示其过期机制,并提供最佳实践指南,助你掌握数据生命周期管理的艺术,让数据优雅退场。
711 0
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用的算法是哈希槽分区算法。Redis集群中有16384个哈希槽(槽的范围是 0 -16383,哈希槽),将不同的哈希槽分布在不同的Redis节点上面进行管理,也就是说每个Redis节点只负责一部分的哈希槽。在对数据进行操作的时候,集群会对使用CRC16算法对key进行计算并对16384取模(slot = CRC16(key)%16383),得到的结果就是 Key-Value 所放入的槽,通过这个值,去找到对应的槽所对应的Redis节点,然后直接到这个对应的节点上进行存取操作
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不⼀致 2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中 这种⽅案能解决1 ⽅案的问题,但是在⾼并发下性能较低,⽽且仍然会出现数据不⼀致的问题,⽐如线程1删除了 Redis缓存数据,正在更新Mysql,此时另外⼀个查询再查询,那么就会把Mysql中⽼数据⼜查到 Redis中 1. 使用MQ异步同步, 保证数据的最终一致性 我们项目中会根据业务情况 , 使用不同的方案来解决Redis和Mysql的一致性问题 : 1. 对于一些一致性要求不高的场景 , 不做处理例如 : 用户行为数据 ,
|
NoSQL Redis
Redis的数据淘汰策略有哪些 ?
Redis 提供 8 种数据淘汰策略: 淘汰易失数据(具有过期时间的数据) 1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 2. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰 3. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 4. volatile-random:从已设置过期
|
NoSQL Redis
Redis的数据持久化策略有哪些 ?
Redis 提供了两种方式,实现数据的持久化到硬盘。 1. RDB 持久化(全量),是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 2. AOF持久化(增量),以日志的形式记录服务器所处理的每一个写、删除操作 RDB和AOF一起使用, 在Redis4.0版本支持混合持久化方式 ( 设置 aof-use-rdb-preamble yes )