Skip to content
标签
欢迎扫码关注公众号

使用 redis-shake 同步 Redis 数据

使用阿里开源的 redis-shake 工具同步 Redis 数据(这个开源工具貌似暂时仅支持单向同步,我记得阿里云提供的工具里貌似是支持双向同步的)。

这里是同步( sync )的示例,另外还支持从备份文件恢复( restore )数据。

官方仓库的 README 里有详细的介绍,这里仅记录下自己的操作步骤,供以后参考。

  1. 下载

    Releases 页面下载后解压(这里使用的是 3.1.5 版本):

    bash
    tar -xzvf redis-shake-linux-amd64.tar.gz
  2. 同步的配置文件 sync-prod-k8s-uat.toml

    这里是在默认提供的 sync.toml 基础上修改了些配置(源和目标服务器的版本、地址和 ncpu)。
    配置项不多,备注也写的很详细。

    ini
    type = "sync"
    
    [source]
    version = 6.0 # redis version, such as 2.8, 4.0, 5.0, 6.0, 6.2, 7.0, ...
    address = "10.0.1.14:6379"
    username = "" # keep empty if not using ACL
    password = "" # keep empty if no authentication is required
    tls = false
    elasticache_psync = "" # using when source is ElastiCache. ref: https://github.com/alibaba/RedisShake/issues/373
    
    [target]
    type = "standalone" # "standalone" or "cluster"
    version = 6.0 # redis version, such as 2.8, 4.0, 5.0, 6.0, 6.2, 7.0, ...
    # When the target is a cluster, write the address of one of the nodes.
    # redis-shake will obtain other nodes through the `cluster nodes` command.
    address = "10.0.1.96:6379"
    username = "" # keep empty if not using ACL
    password = "" # keep empty if no authentication is required
    tls = false
    
    [advanced]
    dir = "data"
    
    # runtime.GOMAXPROCS, 0 means use runtime.NumCPU() cpu cores
    ncpu = 0
    
    # pprof port, 0 means disable
    pprof_port = 0
    
    # metric port, 0 means disable
    metrics_port = 0
    
    # log
    log_file = "redis-shake.log"
    log_level = "info" # debug, info or warn
    log_interval = 5 # in seconds
    
    # redis-shake gets key and value from rdb file, and uses RESTORE command to
    # create the key in target redis. Redis RESTORE will return a "Target key name
    # is busy" error when key already exists. You can use this configuration item
    # to change the default behavior of restore:
    # panic:   redis-shake will stop when meet "Target key name is busy" error.
    # rewrite: redis-shake will replace the key with new value.
    # ignore:  redis-shake will skip restore the key when meet "Target key name is busy" error.
    rdb_restore_command_behavior = "rewrite" # panic, rewrite or skip
    
    # pipeline
    pipeline_count_limit = 1024
    
    # Client query buffers accumulate new commands. They are limited to a fixed
    # amount by default. This amount is normally 1gb.
    target_redis_client_max_querybuf_len = 1024_000_000
    
    # In the Redis protocol, bulk requests, that are, elements representing single
    # strings, are normally limited to 512 mb.
    target_redis_proto_max_bulk_len = 512_000_000
  3. 执行同步命令

    bash
    ./redis-shake sync-prod-k8s-uat.toml
  4. 日志 data/redis-shake.log

    json
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"GOOS: linux, GOARCH: amd64"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"Ncpu: 0, GOMAXPROCS: 2"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"pid: 31083"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"pprof_port: 0"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"No lua file specified, will not filter any cmd."}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"auth successful. address=[10.0.1.96:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"redisWriter connected to redis successful. address=[10.0.1.96:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"auth successful. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"psyncReader connected to redis successful. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"start save RDB. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"send [replconf listening-port 10007]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"send [PSYNC ? -1]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"receive [FULLRESYNC 0d23bc30bd360693a56e78e71f6eee3f7c920dd5 0]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"source db is doing bgsave. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"source db bgsave finished. timeUsed=[0.83]s, address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"received rdb length. length=[41477926]"}
    {"level":"info","time":"2022-10-08T14:52:41+08:00","message":"create dump.rdb file. filename_path=[dump.rdb]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"save RDB finished. address=[10.0.1.14:6379], total_bytes=[41477926]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"start send RDB. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB version: 9"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[redis-ver], value=[6.0.3]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[redis-bits], value=[64]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[ctime], value=[1665211961]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[used-mem], value=[74568984]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB repl-stream-db: 0"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[repl-id], value=[0d23bc30bd360693a56e78e71f6eee3f7c920dd5]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[repl-offset], value=[0]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB AUX fields. key=[aof-preamble], value=[0]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"RDB resize db. db_size=[553969], expire_size=[1708]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"start save AOF. address=[10.0.1.14:6379]"}
    {"level":"info","time":"2022-10-08T14:52:42+08:00","message":"AOFWriter open file. filename=[0.aof]"}
    {"level":"info","time":"2022-10-08T14:52:45+08:00","message":"LUA script: [if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil;end; local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); return 0; else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; return nil;]"}
    {"level":"info","time":"2022-10-08T14:52:45+08:00","message":"LUA script: [if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);]"}
    {"level":"info","time":"2022-10-08T14:52:45+08:00","message":"send RDB finished. address=[10.0.1.14:6379], repl-stream-db=[0]"}
    {"level":"info","time":"2022-10-08T14:52:46+08:00","message":"syncing aof. allowOps=[110794.20], disallowOps=[0.00], entryId=[553970], InQueueEntriesCount=[0], unansweredBytesCount=[0]bytes, diff=[14], aofReceivedOffset=[14], aofAppliedOffset=[0]"}
    {"level":"info","time":"2022-10-08T14:52:46+08:00","message":"AOFReader open file. aof_filename=[0.aof]"}
    {"level":"info","time":"2022-10-08T14:52:51+08:00","message":"syncing aof. allowOps=[110796.80], disallowOps=[0.00], entryId=[553983], InQueueEntriesCount=[0], unansweredBytesCount=[0]bytes, diff=[0], aofReceivedOffset=[144991], aofAppliedOffset=[144991]"}

Page Layout Max Width

Adjust the exact value of the page width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the page layout
A ranged slider for user to choose and customize their desired width of the maximum width of the page layout can go.

Content Layout Max Width

Adjust the exact value of the document content width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the content layout
A ranged slider for user to choose and customize their desired width of the maximum width of the content layout can go.