乐趣区

关于java:Redis哨兵与集群数据迁移同步实践说明

1. 迁徙工具比对

  1. redis-migrate-tool

    redis-migrate-tool 是唯品会开源的一款 Redis 异构集群之间的数据实时迁徙工具,不过曾经有两年没有更新了,我集体感觉这是一款比较完善的工具,特地是数据校验,具体性能介绍见 GitHub:参考地址

  2. RedisShake

    RedisShake 是阿里云基于豌豆荚开源的 redis-port 进行二次开发的一个反对 Redis 异构集群实时同步的工具,它和 redis-migrate-tool 相比拟,我感觉它的长处在于反对前缀 key 的同步,反对多 DB 同步,而 redis-migrate-tool 只能全量同步,并且如果源做了分库,同步到指标 Redis 的时候都同步到了 db0 一个库外面了,这对于做了分库场景的业务是不可行的,对于 RedisShake 的具体性能介绍见 GitHub:参考地址

  3. redis-port
    redis-port 是豌豆荚当年为了让大家不便从 redis 迁徙到 Codis 开源的一个 Redis 数据迁徙工具,当初也曾经很久没更新了,对于它的性能也用能够参见 GitHub:参考地址

2. 迁徙工具装置与配置

  1. RedisShake 的装置

    间接下载二进制包进行装置:

    下载地址

  2. 配置文件批改

    redis-shake.conf 配置文件:

    # 以后配置文件的版本号,请不要批改该值。conf.version = 1
    # ------------------------------------------------------
    # id
    id = redis-shake
    # log file,日志文件,不配置将打印到 stdout (e.g. /var/log/redis-shake.log)
    log.file =
    # log level: "none", "error", "warn", "info", "debug". default is "info".
    log.level = info
    # pid path,过程文件存储地址(e.g. /var/run/),不配置将默认输入到执行上面,
    # 留神这个是目录,真正的 pid 是 `{pid_path}/{id}.pid`
    pid_path = 
    
    # pprof port.
    system_profile = 9310
    # restful port, set -1 means disable, in `restore` mode RedisShake will exit once finish restoring RDB only if this value
    # is -1, otherwise, it'll wait forever.
    # restful port,查看 metric 端口, - 1 示意不启用,如果是 `restore` 模式,只有设置为 - 1 才会在实现 RDB 复原后退出,否则会始终 block。http_profile = 9320
    
    # parallel routines number used in RDB file syncing. default is 64.
    # 启动多少个并发线程同步一个 RDB 文件。parallel = 32
    
    # 源端 redis 的类型,反对 standalone,sentinel,cluster 和 proxy 四种模式,留神:目前 proxy 只用于 rump 模式。source.type = sentinel
    # 源 redis 地址。对于 sentinel 或者开源 cluster 模式,输出格局为 "master 名字: 拉取角色为 master 或者 slave@sentinel 的地址",别的 cluster
    # 架构,比方 codis, twemproxy, aliyun proxy 等须要配置所有 master 或者 slave 的 db 地址。source.address = mymaster:master@10.10.20.101:26379;10.10.20.102:26379;10.10.20.103:26379
    # password of db/proxy. even if type is sentinel.
    source.password_raw = 
    # auth type, don't modify it
    source.auth_type = auth
    # tls enable, true or false. Currently, only support standalone.
    # open source redis does NOT support tls so far, but some cloud versions do.
    source.tls_enable = false
    # input RDB file.
    # used in `decode` and `restore`.
    # if the input is list split by semicolon(;), redis-shake will restore the list one by one.
    # 如果是 decode 或者 restore,这个参数示意读取的 rdb 文件。反对输出列表,例如:rdb.0;rdb.1;rdb.2
    # redis-shake 将会挨个进行复原。source.rdb.input = local
    
    # 如果 db 节点 / 输出的 rdb 有 5 个,但 rdb.parallel=3,那么一次只会
    # 并发拉取 3 个 db 的全量数据,直到某个 db 的 rdb 拉取结束并进入增量,才会拉取第 4 个 db 节点的 rdb,# 以此类推,最初会有 len(source.address)或者 len(rdb.input)个增量线程同时存在。source.rdb.parallel = 0
    # for special cloud vendor: ucloud
    # used in `decode` and `restore`.
    # ucloud 集群版的 rdb 文件增加了 slot 前缀,进行特判剥离: ucloud_cluster。source.rdb.special_cloud = 
    
    # 目标 redis 的类型,反对 standalone,sentinel,cluster 和 proxy 四种模式。target.type = cluster
    
    target.address = 10.10.20.101:7000;10.10.20.102:7000;10.10.20.103:7000
    # password of db/proxy. even if type is sentinel.
    target.password_raw = Redis1234{}
    # auth type, don't modify it
    target.auth_type = auth
    # all the data will be written into this db. < 0 means disable.
    target.db = 0
    # tls enable, true or false. Currently, only support standalone.
    # open source redis does NOT support tls so far, but some cloud versions do.
    target.tls_enable = false
    # output RDB file prefix.
    # used in `decode` and `dump`.
    # 如果是 decode 或者 dump,这个参数示意输入的 rdb 前缀,比方输出有 3 个 db,那么 dump 别离是:
    # ${output_rdb}.0, ${output_rdb}.1, ${output_rdb}.2
    target.rdb.output = local_dump
    
    # e.g., target.version = 4.0
    target.version =
    
    # 用于解决过期的键值,当迁徙两端不统一的时候,目标端须要加上这个值
    fake_time =
    
    # 当源目标有反复 key,是否进行覆写
    # rewrite 示意源端笼罩目标端。# none 示意一旦产生过程间接退出。# ignore 示意保留目标端 key,疏忽源端的同步 key。该值在 rump 模式下没有用。key_exists = rewrite
    
    # 指定的 db 被通过,比方 0;5;10 将会使 db0, db5, db10 通过, 其余的被过滤
    filter.db.whitelist =
    # 指定的 db 被过滤,比方 0;5;10 将会使 db0, db5, db10 过滤,其余的被通过
    filter.db.blacklist =
    # 反对按前缀过滤 key,只让指定前缀的 key 通过,分号分隔。比方指定 abc,将会通过 abc, abc1, abcxxx
    filter.key.whitelist =
    # 反对按前缀过滤 key,不让指定前缀的 key 通过,分号分隔。比方指定 abc,将会阻塞 abc, abc1, abcxxx
    filter.key.blacklist =
    # filter given slot, multiple slots are separated by ';'.
    # e.g., 1;2;3
    # used in `sync`.
    # 指定过滤 slot,只让指定的 slot 通过
    filter.slot =
    # filter lua script. true means not pass. However, in redis 5.0, the lua 
    # converts to transaction(multi+{commands}+exec) which will be passed.
    # 管制不让 lua 脚本通过,true 示意不通过
    filter.lua = false
    
    # 失常 key 如果不大,那么都是间接调用 restore 写入到目标端,如果 key 对应的 value 字节超过了给定
    # 的值,那么会分批顺次一个一个写入。如果目标端是 Codis,这个须要置为 1,具体起因请查看 FAQ。# 如果目标端大版本小于源端,也倡议设置为 1。big_key_threshold = 524288000
    
    # enable metric
    # used in `sync`.
    # 是否启用 metric
    metric = true
    # print in log
    # 是否将 metric 打印到 log 中
    metric.print_log = false
    
    # sender information.
    # sender flush buffer size of byte.
    # used in `sync`.
    # 发送缓存的字节长度,超过这个阈值将会强行刷缓存发送
    sender.size = 104857600
    # sender flush buffer size of oplog number.
    # used in `sync`. flush sender buffer when bigger than this threshold.
    # 发送缓存的报文个数,超过这个阈值将会强行刷缓存发送,对于目标端是 cluster 的状况,这个值
    # 的调大将会占用局部内存。sender.count = 4095
    
    # 用于 metric 统计时延的队列
    sender.delay_channel_size = 65535
    
    # enable keep_alive option in TCP when connecting redis.
    # the unit is second.
    # 0 means disable.
    # TCP keep-alive 保活参数,单位秒,0 示意不启用。keep_alive = 0
    
    # 每次 scan 的个数,不配置则默认 100.
    scan.key_number = 50
    # 有些版本具备非凡的格局,与一般的 scan 命令有所不同,咱们进行了非凡的适配。目前反对腾讯云的集群版 "tencent_cluster"
    # 和阿里云的集群版 "aliyun_cluster",正文主从版不须要配置,只针对集群版。scan.special_cloud =
    # used in `rump`.
    # we support to fetching data from given file which marks the key list.
    # 有些云版本,既不反对 sync/psync,也不反对 scan,咱们反对从文件中进行读取所有 key 列表并进行抓取:一行一个 key。scan.key_file =
    
    # limit the rate of transmission. Only used in `rump` currently.
    # e.g., qps = 1000 means pass 1000 keys per second. default is 500,000(0 means default)
    qps = 200000
    
    # enable resume from break point, please visit xxx to see more details.
    # 断点续传开关
    resume_from_break_point = false
    
    # replace hash tag.
    # used in `sync`.
    replace_hash_tag = false
    

次要配置项阐明:

# 源 Redis 的类型,哨兵模式采纳 sentinel
source.type = sentinel
# 源 Redis 的地址信息,如果是哨兵,格局:哨兵名称: 主从标识 @节点地址信息
source.address = mymaster:master@10.10.20.101:26379;10.10.20.102:26379;10.10.20.103:26379
# 源 Redis 的明码信息,没有明码认证,留空即可
source.password_raw = 
# 源 Redis 的认证标识,不论有无明码认证,都不必批改
source.auth_type = auth
# 指标 Redis 的类型,这里所填的指标是集群
target.type = cluster
# 指标 Redis 的地址信息,多个地址以; 分号分隔,留神这里要填的对立为主节点或从节点信息
target.address = 10.10.20.101:7000;10.10.20.102:7000;10.10.20.103:7000
# 指标 Redis 的明码信息
target.password_raw = Redis1234{}
# 指标 Redis 的认证标识,不必批改
target.auth_type = auth
# 指标 Redis 的存储数据库,如果为正数,代表不启用该性能,如果指定某个库,会将源数据全副写入
target.db = 0
# 当存在雷同的 keys,解决计划:# rewrite 示意源端笼罩目标端。# none 示意一旦产生过程间接退出。# ignore 示意保留目标端 key,疏忽源端的同步 key。该值在 rump 模式下没有用。key_exists = rewrite

3. 数据同步解决

  1. 数据同步命令

    ./redis-shake -conf=redis-shake.conf -type=sync

type 能够反对 sync, restore, dump, decode, rump。全量 + 增量同步抉择 sync

  1. 日志后果信息

    同步分为三个阶段:

    A. 期待源端 save rdb 结束,日志如下

    2019/06/06 15:14:56 [INFO] dbSyncer[0] + waiting source rdb
    2019/06/06 15:14:57 [INFO] dbSyncer[0] - waiting source rdb
    2019/06/06 15:14:57 [INFO] dbSyncer[0] + waiting source rdb

B. 全量同步阶段,显示百分比:

2019/06/06 15:15:41 [INFO] dbSyncer[0] total=924836132 -      9155943 [0%]  entry=2109
2019/06/06 15:15:42 [INFO] dbSyncer[0] total=924836132 -     16107663 [1%]  entry=4411
2019/06/06 15:15:43 [INFO] dbSyncer[0] total=924836132 -     22914262 [2%]  entry=6750
2019/06/06 15:15:44 [INFO] dbSyncer[0] total=924836132 -     29707595 [3%]  entry=9060
2019/06/06 15:15:45 [INFO] dbSyncer[0] total=924836132 -     35741354 [3%]  entry=11067
2019/06/06 15:15:46 [INFO] dbSyncer[0] total=924836132 -     42911547 [4%]  entry=13480

C. 增量同步,呈现字样 sync rdb done 后,以后 dbSyncer 进入增量同步:

2019/07/09 16:34:05 [INFO] dbSyncer[0] sync:  +forwardCommands=1      +filterCommands=0      +writeBytes=4
2019/07/09 16:34:06 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0
2019/07/09 16:34:07 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0
2019/07/09 16:34:08 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0
2019/07/09 16:34:09 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0
2019/07/09 16:34:10 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0
2019/07/09 16:34:11 [INFO] dbSyncer[0] sync:  +forwardCommands=0      +filterCommands=0      +writeBytes=0

其中 forwardCommands 示意发送的命令个数,filterCommands 示意过滤的命令个数,比方 opinfo 或者指定了 filter 都会被过滤,writeBytes 示意发送的字节数。

4. 数据校验解决

  1. 数据校验工具

    redis-full-check 通过全量比照源端和目标端的 redis 中的数据的形式来进行数据校验。

    Redis-full-check

    下载地址

  2. 校验执行命令

    ./redis-full-check -s '10.10.20.102:6379' -p ''-t'10.10.20.101:7000;10.10.20.102:7000;10.10.20.103:7000'-a'Redis1234{}' --targetdbtype=1 --metric  --result=result.1            

配置同步源地址与指标地址信息,开启 metric 会输入剖析信息,result 会将校验后果做汇总记录。

具体参数阐明:

  -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
  1. 查看比对后果

    查看 result 后果信息:

    [root@localhost redis-full-check-1.4.8]# less result.1 

校验后果:

0       lack_target     single23        
1       lack_target     test    
9       value   single2

第一列代表数据库编号,第二列代表抵触类型,第三列代表抵触的 key。

抵触类型蕴含:

lack_soure: field 存在于源端 key,field 不存在与目标端 key。

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

value: field 存在于源端 key 和目标端 key,然而 field 对应的 value 不同。

要查看更为具体的信息,能够通过 sqlite 查问:

[root@localhost redis-full-check-1.4.8]# sqlite3 result.db.3
SQLite version 3.7.17 2013-05-20 00:56:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
FINAL_RESULT  field         key         
sqlite> select * from key;
1|single23|string|lack_target|0|2|0
2|test|string|lack_target|1|4|0
3|single2|string|value|9|1|9

信息列对应关系: id, key, type, conflict_type, db, source_len, target_len


本文由 mirson 创作分享,如需进一步交换,请加 QQ 群:19310171 或拜访 www.softart.cn

退出移动版