Redis遷移工具之Redis-shake


  Redis-shake is a tool for synchronizing data between two redis databases. Redis-shake是一個用於在兩個redis之間同步數據的工具,滿足用戶非常靈活的同步、遷移需求

  GitHub地址:https://github.com/alibaba/RedisShake

 

1. 下載,解壓

wget -c https://github.com/alibaba/RedisShake/releases/download/release-v1.6.24-20191220/redis-shake-1.6.24.tar.gz
tar -zxvf
redis-shake-1.6.24.tar.gz
cd  redis-shake-1.6.24.tar.gz

2. 配置文件

# this is the configuration of redis-shake.

# id
id = redis-shake
# log file,日志文件,不配置將打印到stdout
log_file =

# pprof port
system_profile = 9310
# restful port,查看metric端口
http_profile = 9320

# runtime.GOMAXPROCS, 0 means use cpu core number: runtime.NumCPU()
ncpu = 0

# parallel routines number used in RDB file syncing.
parallel = 4

# input RDB file. read from stdin, default is stdin ('/dev/stdin').
# used in `decode` and `restore`.
# 如果是decode或者restore,這個參數表示讀取的rdb文件
input_rdb = local_dump

# output RDB file. default is stdout ('/dev/stdout').
# used in `decode` and `dump`.
# 如果是decode或者dump,這個參數表示輸出的rdb
output_rdb = local_dump

# source redis configuration.
# used in `dump` and `sync`.
# ip:port
# 源redis地址
source.address = 127.0.0.1:20441
# password.
source.password_raw = kLNIl691OZctWST
# auth type, don't modify it
source.auth_type = auth
# version number, default is 6 (6 for Redis Version <= 3.0.7, 7 for >=3.2.0)
source.version = 6

# target redis configuration. used in `restore` and `sync`.
# used in `restore` and `sync`.
# ip:port
# 目的redis地址
target.address = 10.101.72.137:20551
# password.
target.password_raw = kLNIl691OZctWST
# auth type, don't modify it
target.auth_type = auth
# version number, default is 6 (6 for Redis Version <= 3.0.7, 7 for >=3.2.0)
target.version = 6
# all the data will come into this db. < 0 means disable.
# used in `restore` and `sync`.
target.db = -1

# use for expire key, set the time gap when source and target timestamp are not the same.
# 用於處理過期的鍵值,當遷移兩端不一致的時候,目的端需要加上這個值
fake_time =

# force rewrite when destination restore has the key
# used in `restore` and `sync`.
# 當源目的有重復key,是否進行覆寫
rewrite = true

# filter db or key or slot
# choose these db, e.g., 5, only choose db5. defalut is all.
# used in `restore` and `sync`.
# 支持過濾db,只讓指定的db通過
filter.db =
# filter key with prefix string. multiple keys are separated by ';'.
# e.g., a;b;c
# default is all.
# used in `restore` and `sync`.
# 支持過濾key,只讓指定的key通過,分號分隔
filter.key =
# filter given slot, multiple slots are separated by ';'.
# e.g., 1;2;3
# used in `sync`.
# 指定過濾slot,只讓指定的slot通過
filter.slot =

# big key threshold, the default is 500 * 1024 * 1024. The field of the big key will be split in processing.
# 我們對大key有特殊的處理,此處需要指定大key的閾值
big_key_threshold = 524288000

# use psync command.
# used in `sync`.
# 默認使用sync命令,啟用將會使用psync命令
psync = false

# enable metric
# used in `sync`.
# 是否啟用metric
metric = true
# print in log
# 是否將metric打印到log中
metric.print_log = true

# heartbeat
# send heartbeat to this url
# used in `sync`.
# 心跳的url地址,redis-shake將會發送到這個地址
heartbeat.url = http://127.0.0.1:8000
# interval by seconds
# 心跳保活周期
heartbeat.interval = 3
# external info which will be included in heartbeat data.
# 在心跳報文中添加額外的信息
heartbeat.external = test external
# local network card to get ip address, e.g., "lo", "eth0", "en0"
# 獲取ip的網卡
heartbeat.network_interface =

# sender information.
# sender flush buffer size of byte.
# used in `sync`.
# 發送緩存的字節長度,超過這個閾值將會強行刷緩存發送
sender.size = 104857600
# sender flush buffer size of oplog number.
# used in `sync`.
# 發送緩存的報文個數,超過這個閾值將會強行刷緩存發送
sender.count = 5000
# delay channel size. once one oplog is sent to target redis, the oplog id and timestamp will also stored in this delay queue. this timestamp will be used to calculate the time delay when receiving ack from target redis.
# used in `sync`.
# 用於metric統計時延的隊列
sender.delay_channel_size = 65535

# ----------------splitter----------------
# below variables are useless for current opensource version so don't set.

# replace hash tag.
# used in `sync`.
replace_hash_tag = false

# used in `restore` and `dump`.
extra = false

 

摘取部分內容:

這部分應該是用戶最困惑的地方,為了滿足用戶的靈活配置,目前開放了較多的配置項,但用戶一開始使用並不需要管這么多的項。默認sync模式只需要配置以下幾個內容:

source.type: 源redis的類型,支持一下4種類型:
standalone: 單db節點/主從版模式。如果源端是從多個db節點拉取就選擇這個模式,即便是codis等開源的proxy-db架構。
sentinel: sentinel模式。
cluster: 集群模式。開源的cluster。對於阿里雲來說,用戶目前無法拉取db的地址,所以此處只能是proxy。
proxy: proxy模式。如果是阿里雲redis的集群版,從proxy拉取/寫入請選擇proxy,從db拉取請選擇cluster。正常cluster到cluster同步源端請選擇cluster模式,proxy模式目前只用於rump。。
source.address: 源redis的地址,從1.6版本開始我們支持集群版,不同的類型對應不同的地址:
standalone模式下,需要填寫單個db節點的地址,主從版需要輸入master或者slave的地址。
sentinel模式下,需要填寫sentinel_master_name:master_or_slave@sentinel_cluster_address。sentinel_master_name表示sentinel配置下master的名字,master_or_slave表示從sentinel中選擇的db是master還是slave,sentinel_cluster_address表示sentinel的單節點或者集群地址,其中集群地址以分號(;)分割。例如:mymaster:master@127.0.0.1:26379;127.0.0.1:26380。注意,如果是sentinel模式,目前只能拉取一個master或者slave信息,如果需要拉取多個節點,需要啟動多個shake。
cluster模式下,需要填寫集群地址,以分號(;)分割。例如:10.1.1.1:20331;10.1.1.2:20441。同樣也支持上面sentinel介紹的自動發現機制,包含@即可,參考3.2。
proxy模式下,需要填寫單個proxy的地址,此模式目前僅用於rump。
source.password_raw:源redis的密碼。
target.type: 目的redis的類型,與source.type一致。注意,目的端如果是阿里雲的集群版,類型請填寫proxy,填寫cluster只會同步db0。
target.address:目的redis的地址。從1.6版本開始我們支持集群版,不同的類型對應不同的地址。 standalone模式,參見source.address。
sentinel模式,需要填寫sentinel_master_name@sentinel_cluster_address。sentinel_master_name表示sentinel配置下master的名字,sentinel_cluster_address表示sentinel的單節點或者集群地址,其中集群地址以分號(;)分割。例如:mymaster@127.0.0.1:26379;127.0.0.1:26380
cluster模式,參見source.address。
proxy模式下,填寫proxy的地址,如果是多個proxy,則round-robin循環負載均衡連接,保證一個源端db連接只會對應一個proxy。如果是阿里雲的集群版請選擇這種模式。
target.password_raw:目的redis的密碼。
用戶配置完配置文件,然后以不同的模式啟動即可:./redis-shake -conf=redis-shake.conf -type=sync。

3.1 單個節點到單個節點配置舉例。
source.type: standalone
source.address: 10.1.1.1:20441
source.password_raw: 12345
target.type: standalone
target.address: 10.1.1.1:20551
target.password_raw: 12345
3.2 集群版cluster到集群版cluster配置舉例
source.type: cluster
source.address: 10.1.1.1:20441;10.1.1.1:20443;10.1.1.1:20445
source.password_raw: 12345
target.type: cluster
target.address: 10.1.1.1:20551;10.1.1.1:20553;10.1.1.1:20555
target.password_raw: 12345
  對於source.address或者target.address,需要配置源端的所有集群中db節點列表以及目的端集群所有db節點列表,用戶也可以啟用自動發現機制,地址以'@'開頭,redis-shake將會根據cluster nodes命令自動去探測有幾個節點。對於source.address,用戶可以在'@'前面配置master(默認)或者slave表示分表從master或者slave進行拉取;對於target.address,只能是master或者不配置:

source.type: cluster
source.address: master@10.1.1.1:20441 # 將會自動探測到10.1.1.1:20441集群下的所有節點,並從所有master進行拉取。同理如果是slave@10.1.1.1:20441將會掃描集群下的所有slave節點。
source.password_raw: 12345
target.type: cluster
target.address: @10.1.1.1:20551 # 將會自動探測到10.1.1.1:20551集群下的所有節點,並寫入所有master。
target.password_raw: 12345
  以上的說明是開源cluster,當然,源端也可以是別的集群架構模式,比如帶proxy的集群(比如codis,或者別的雲集群架構,但這種情況下有些不支持自動發現,需要手動配置所有master或者slave的地址),那么需要選擇db節點進行拉取,source.type同樣選擇cluster,source.address后面跟所有db的地址(只要主或者從的其中一個即可)。

3.3 集群版cluster到proxy配置舉例
source.type: cluster
source.address: 10.1.1.1:20441;10.1.1.1:20443;10.1.1.1:20445;10.1.1.1:20447
source.password_raw: 12345
target.type: proxy
target.address: 10.1.1.1:30331;10.1.1.1:30441;10.1.1.1:30551
target.password_raw: 12345
  source.address同樣支持自動發現機制,參考3.2。此外,target.address為proxy的地址,proxy支持roundrobin寫入,也就是說,對於這個配置來說,10.1.1.1:20441和10.1.1.1:20447將會寫入10.1.1.1:3033110.1.1.1:20443寫入10.1.1.1:3044110.1.1.1:20445寫入10.1.1.1:30551。
  如3.2中所述,源端也可以是別的集群架構模式。

3.4 主從版/單節點到cluster配置舉例
source.type: standalone
source.address: 10.1.1.1:20441
source.password_raw: 12345
target.type: cluster
target.address: 10.1.1.1:30331;10.1.1.1:30441;10.1.1.1:30551
target.password_raw: 12345

  更詳細的查看: https://github.com/alibaba/RedisShake/wiki/%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E9%85%8D%E7%BD%AE%EF%BC%9F

 

3. 啟動

啟動二進制:./redis-shake.linux -conf=redis-shake.conf -type=xxx # xxx為sync, restore, dump, decode, rump其中之一,全量+增量同步請選擇sync。 mac下請使用redis-shake.darwin,windows請用redis-shake.windows.

 

4. 校驗同步(redis-full-check  github:https://github.com/alibaba/RedisFullCheck)

  在Redis遷移完成后進行數據校驗可以檢查數據的一致性。

  1) 下載,解壓

wget -c https://github.com/alibaba/RedisFullCheck/releases/download/release-v1.4.7-20191203/redis-full-check-1.4.7.tar.gz

tar -zxvf redis-full-check-1.4.7.tar.gz && cd redis-full-check-1.4.7.tar.gz

 

  2) 執行數據校驗命令

./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

  注意: 如果目標是集群的話,需要指定--targetdbtype 類型為1

  

表 1. redis-full-check常用選項說明
選項 說明 示例值
-s 源端Redis的連接地址和端口。
 
說明
  • 如果源Redis為集群版,每個集群地址間需要以半角分號(;)分割不同的連接地址。
  • 集群地址前后需要添加半角雙引號(")。
  • 該選項必填。
 
r-bp1xxxxxxxxxxxxx.redis.rds.aliyuncs.com:6379
 
"10.xx.xx.1:7000;10.xx.xx.1:7001;10.xx.xx.2:7002;10.xx.xx.2:7003"
-p 源端Redis的密碼。 SourcePwd233
-t 目的端Redis的連接地址和端口。
 
說明
  • 如果目的Redis為集群版,每個集群地址間需要以半角分號(;)分割不同的連接地址。
  • 集群地址前后需要添加半角雙引號(")。
  • 該選項必填。
 
r-bp1xxxxxxxxxxxxx.redis.rds.aliyuncs.com:6379
 
"10.xx.xx.1:7000;10.xx.xx.1:7001;10.xx.xx.2:7002;10.xx.xx.2:7003"
-a 目的端Redis的密碼。 TargetPwd233
--sourcedbtype 源庫的類別:
  • 0:單節點版、主從版
  • 1:集群版
  • 2:阿里雲/騰訊雲
--sourcedbtype=1
--sourcedbfilterlist 源端Redis指定需要校驗的DB。
 
說明
  • 開源集群版Redis無需填寫該選項。
  • 非開源集群版Redis不指定該選項表示校驗所有DB。
  • 多個DB之間使用半角分號(;)連接。
--sourcedbfilterlist=0;1;2
--targetdbtype 目的庫的類別:
  • 0:單節點版、主從版
  • 1:集群版
  • 2:阿里雲/騰訊雲
--targetdbtype=0
--targetdbfilterlist 目的端Redis指定需要校驗的DB。
 
說明
  • 開源集群版Redis無需填寫該選項。
  • 非開源集群版Redis不指定該選項表示校驗所有DB。
  • 多個DB之間使用半角分號(;)連接。
--targetdbfilterlist=0;1;2
-d 異常數據列表保存的文件名稱,默認為result.db。 xxx.db
--comparetimes 校驗次數。
  • 該選項不填則默認為3次。
  • 最小值為1。
  • 無最大值,建議不超過5次。
--comparetimes=1
-m 校驗模式。
  • 1:全量校驗
  • 2:僅校驗value的長度
  • 3:僅校驗key是否存在
  • 4:全量對比的情況下,忽略大key的比較
1
--qps 限速閾值。
 
說明
  • 最小值為1。
  • 最大值取決於服務器性能。
--qps=10
--filterlist 需要比較的key列表,以豎線(|)分割。
 
說明
  • abc*:表示匹配所有abc開頭的key。
  • abc:表示僅匹配abc這個key。
--filterlist=abc*|efg|m*

 

  3)校驗結果驗證

 

   i) 執行查看命令

sqlite3 result.db.3

  ii)查看異常表數據

select * from key;

 

 

5. 數據的導入與導出

  

數據導出:
./redis-shake.linux -conf=redis-shake.conf -type=dump

數據導入:
./redis-shake.linux -conf=redis-shake.conf -type=restore

注意:
    數據導入的時候需要配置要導入的類型與數據源
    source.rdb.input = local_dump.0

 

 

 

 

官方一些說明:

[redis-full-check]

redis-full-check是阿里雲Redis&MongoDB團隊開源的用於校驗2個redis數據是否一致的工具,通常用於redis數據遷移(redis-shake)后正確性的校驗。
  支持:單節點、主從版、集群版、帶proxy的雲上集群版(阿里雲)之間的同構或者異構對比,版本支持2.x-5.x。

基本原理

  下圖給出了最基本的比較邏輯。
Screen_Shot_2019_03_29_at_8_24_07_PM
  redis-full-check通過全量對比源端和目的端的redis中的數據的方式來進行數據校驗,其比較方式通過多輪次比較:每次都會抓取源和目的端的數據進行差異化比較,記錄不一致的數據進入下輪對比(記錄在sqlite3 db中)。然后通過多倫比較不斷收斂,減少因數據增量同步導致的源庫和目的庫的數據不一致。最后sqlite中存在的數據就是最終的差異結果。
  redis-full-check對比的方向是單向:抓取源庫A的數據,然后檢測是否位於B中,反向不會檢測,也就是說,它檢測的是源庫是否是目的庫的子集。如果希望對比雙向,則需要對比2次,第一次以A為源庫,B為目的庫,第二次以B為源庫,A為目的庫。
  下圖是基本的數據流圖,redis-full-check內部分為多輪比較,也就是黃色框所指示的部分。每次比較,會先抓取比較的key,第一輪是從源庫中進行抓取,后面輪次是從sqlite3 db中進行抓取;抓取key之后是分別抓取key對應的field和value進行對比,然后將存在差異的部分存入sqlite3 db中,用於下次比較。
dataflow

不一致類型

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

比較原理

  對比模式(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不一致的hashsetzset,只重新比較不一致的field,之前已經比較且相同的filed不再比較。這是為了防止對於大key情況下,如果更新頻繁,將會導致校驗永遠不通過的情況。
    • value不一致的list,重新比較key:從源和目的取key、value比較。
  • 每輪之間會停止一定的時間(Interval)。

  對於hashsetzsetlist大key處理采用以下方式:

    • len <= 5192,直接取全量field、value進行比較,使用如下命令:hgetallsmemberszrange 0 -1 withscoreslrange 0 -1
    • len > 5192,使用hscan,sscan,zscan,lrange分批取field和value。

 


 

 

 [redis-shake]

 redis-shake是我們基於redis-port基礎上進行改進的一款產品。它支持解析、恢復、備份、同步四個功能。以下主要介紹同步sync。

  • 恢復restore:將RDB文件恢復到目的redis數據庫。
  • 備份dump:將源redis的全量數據通過RDB文件備份起來。
  • 解析decode:對RDB文件進行讀取,並以json格式解析存儲。
  • 同步sync:支持源redis和目的redis的數據同步,支持全量和增量數據的遷移,支持從雲下到阿里雲雲上的同步,也支持雲下到雲下不同環境的同步,支持單節點、主從版、集群版之間的互相同步。需要注意的是,如果源端是集群版,可以啟動一個RedisShake,從不同的db結點進行拉取,同時源端不能開啟move slot功能;對於目的端,如果是集群版,寫入可以是1個或者多個db結點。
  • 同步rump:支持源redis和目的redis的數據同步,僅支持全量的遷移。采用scan和restore命令進行遷移,支持不同雲廠商不同redis版本的遷移。

基本原理

  redis-shake的基本原理就是模擬一個從節點加入源redis集群,首先進行全量拉取並回放,然后進行增量的拉取(通過psync命令)。如下圖所示:
Screen_Shot_2019_03_29_at_6_23_58_PM

  如果源端是集群模式,只需要啟動一個redis-shake進行拉取,同時不能開啟源端的move slot操作。如果目的端是集群模式,可以寫入到一個結點,然后再進行slot的遷移,當然也可以多對多寫入。
  目前,redis-shake到目的端采用單鏈路實現,對於正常情況下,這不會成為瓶頸,但對於極端情況,qps比較大的時候,此部分性能可能成為瓶頸,后續我們可能會計划對此進行優化。另外,redis-shake到目的端的數據同步采用異步的方式,讀寫分離在2個線程操作,降低因為網絡時延帶來的同步性能下降。

高效性

   全量同步階段並發執行,增量同步階段異步執行,能夠達到毫秒級別延遲(取決於網絡延遲)。同時,我們還對大key同步進行分批拉取,優化同步性能。

監控

   用戶可以通過我們提供的restful拉取metric來對redis-shake進行實時監控:curl 127.0.0.1:9320/metric

校驗

   如何校驗同步的正確性?可以采用我們開源的redis-full-check,具體原理可以參考這篇博客

支持

  • 支持2.8-5.0版本的同步。
  • 支持codis。
  • 支持雲下到雲上,雲上到雲上,雲上到雲下(阿里雲目前支持主從版),其他雲到阿里雲等鏈路,幫助用戶靈活構建混合雲場景。

開發中的功能

    1. 斷點續傳。支持斷開后按offset恢復,降低因主備切換、網絡抖動造成鏈路斷開重新同步拉取全量的性能影響。
    2. 多活支持。支持雙向實時同步,搭建異地災備多活。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM