Kubernetes部署RedisShake实现Redis哨兵异地灾备

什么是 RedisShake

RedisShake 是一个用于处理和迁移 Redis 数据的工具,它提供以下特性:

  • Redis 兼容性:RedisShake 兼容从 2.8 到 7.2 的 Redis 版本,并支持各种部署方式,包括单机,主从,哨兵和集群。
  • 云服务兼容性:RedisShake 与主流云服务提供商提供的流行 Redis-like 数据库无缝工作,包括但不限于:
    阿里云-云数据库 Redis 版
    阿里云-云原生内存数据库Tair
    AWS - ElastiCache
    AWS - MemoryDB
  • Module 兼容:RedisShake 与 TairString,TairZSet 和 TairHash 模块兼容。
  • 多种导出模式:RedisShake 支持 PSync,RDB 和 Scan 导出模式。
  • 数据处理:RedisShake 通过自定义脚本实现数据过滤和转换。

Kubernetes部署RedisShake实现Redis哨兵异地灾备

上图是SYNC模式下全量+增量的数据流图,第一次复制向源端发送了之后,源端给它发RDB文件,解析RDB文件放到Pipe中。

它可以通过并发Restore到目的端,同步完成之后就会自动启动增量。增量就是从源端拉取写命令,进行解析过滤,然后再放到目的端,同时还需要接收回复。

架构图

当源端和目的端为单实例节点(Standalone)时,同步架构图如下。

Kubernetes部署RedisShake实现Redis哨兵异地灾备

当源端和目的端都为集群(Cluster)时,同步架构图如下。

从架构图可以看到,数据从源端(Source)同步到目的端(Destination),主要经过 Cluster Reader、Main、Cluster Writer 三部分处理。

Cluster Reader

Cluster Reader 即集群读入类,其根据源端分片数量创建同等数量的 Standalone Reader,每个 Standalone Reader 开启一个协程(Goroutinue)并行的从每个源端分片进行读入,并将数据存入相应的管道(Reader Channel)交付给下一环节处理。

Kubernetes部署RedisShake实现Redis哨兵异地灾备

Sync Reader

优势:数据一致性最佳,对源库影响小,可以实现不停机的切换

原理:RedisShake 模拟 Slave 连接到 Master 节点,Master 会向 RedisShake 发送数据,数据包含全量与增量两部分。全量是一个 RDB 文件,增量是 AOF 数据流,RedisShake 会接受全量与增量将其暂存到硬盘上。全量同步阶段:RedisShake 首先会将 RDB 文件解析为一条条的 Redis 命令,然后将这些命令发送至目的端。增量同步阶段:RedisShake 会持续将 AOF 数据流同步至目的端。

常见问题
连接断开:如果遇到 RedisShake 至源端节点的连接被断开,可通过源端对应节点的运行日志确认,多是因为源端 client-output-buffer-limit replica 参数设置过小,建议适当调高。

Scan Reader

原理介绍

Scan Reader 有 SCAN 和 KSN 两个阶段,SCAN 阶段是全量同步,KSN 阶段是增量同步。

全量数据

Kubernetes部署RedisShake实现Redis哨兵异地灾备

DbSyncer维护了连接链路,它是一个结构体,源端是6379,目的端是一个集群,它代表了一个数据链路。

假如说原来配置的是一个三主三从的集群模式,那么就会开启三个DbSyncer,同时有ID对它进行标识。每个DbSyncer管理一个连接,如6379首先是向RDB文件发送过来,然后Loader会解析出一些信息,包括DB、Key、Type等,然后放到Pipe中。然后需要向目的端写入,写入的时候全量模式支持并发。

从Pipe出来后先进行过滤,因为RedisShake支持DB、Key、Slot这些级别的过滤,用户可以设置黑白名单。正常情况下就可以Restore到目的端,然后再接收回复。对于lua ,可以进行script load,也可以设置过滤lua。对于BigKey,需要根据编码形式进行拆分解析。

增量数据

Kubernetes部署RedisShake实现Redis哨兵异地灾备

全量同步结束之后会自动开启增量同步,增量同步主要是由四个协程完成。

  • 第一个协程定期从源端获取RedisShake的偏移量。

  • 第二个协程主要是从源端拉取写命令。因为原来是模拟源端的一个从,从执行写命令的时候会发送一条Binlog到RedisShake,RedisShake读到之后交给Decoder,然后会将Binlog解析成一个原生命令,同时还会计算一下偏移量。得到命令后有Key,然后就可以进行过滤,再放到Sendbuffer中,Sendbuffer就是最终要发送到目的端的一些写命令。

  • 第三个协程就是Sender,它执行发送逻辑,从Sendbuffer中取出写命令,并不是立即发送过去,它是和Checkpoint绑成一个事务,一块写入目的端。断点续传的原理是会先放到cache里边,就像是一层缓存,然后触发一定条件之后就去执行sendFunc函数。这是一个事务,它会先去写这些增数据,然后再去修改Checkpoint值。

针对于Redis Cluster同步,可以参考下图

Kubernetes部署RedisShake实现Redis哨兵异地灾备

首先源客户发送了一个“SET msg hello”,然后源端会以一个Binlog的形式写入到RedisShake。RedisShake读到之后先解析出原生的写命令,就会调用Send函数。Send函数目的端是一个集群,它需要知道自己应该发送到哪个节点上。

因为集群方式有槽概念,RedisShake还维护了 Slot数组,它的 index就是槽的ID,它对应的值就是槽所在的节点上。Node是一个结构体,里边有一个字段address,就是节点的地址。

调用Send函数的时候,首先需要获取到这个Key是应该发送到哪个节点上,会调用getNodeByKey,实际上就是对Key进行一次Hash,调用的是crc16算法。Key会算到它在哪个槽上,然后再通过下面 Slots数组,就知道这个槽是在哪个节点上,然后再调用do把它写入到 node上,写入之后会Receive目的端的回复。然后我们就需要去检查这个回复是什么,如果是有异常的话,就会直接将这个结果返回过去,再由上一层去进行判断。

假如说是move或者是ask,可能会调用回调函数handleMove或handleAsk两个重定向。

KSN 阶段:默认关闭,可通过 ksn 开启,可以解决 SCAN` 阶段期间遗漏 Key 问题。增量数据同步并不是在 SCAN 阶段结束后才开始,而是与其一同进行,并在 SCAN 阶段结束后持续进行,直到退出 RedisShake。

ksn 使用 Redis keyspace notifications 能力来订阅 Key 的变化。具体来说,RedisShake 会使用 psubscribe 命令订阅 keyevent@*:*,当 Key 发生变化时,RedisShake 会收到发生修改的 Key,之后使用 DUMP 与 RESTORE 命令来从源端读取 Key 的内容,并写入目标端。

  • Redis 在默认情况下不会开启 notify-keyspace-events 配置,需要手动开启,保证值中含有 AE。
  • 如果在 KSN 阶段出现源端将连接断开,考虑适当调高 client-output-buffer-limit pubsub 的值。802
  • Redis keyspace notifications 不会感知到 FLUSHALL 与 FLUSHDB 命令,因此在使用 ksn 参数时,需要确保源端数据库不会执行这两个命令。

性能影响

SCAN 与 KSN 阶段均使用 DUMP 命令来获取数据,DUMP 命令是 CPU 密集命令,会对源端造成较高压力。需要小心使用,避免影响源端实例的可用性。

  • 对于 SCAN 阶段,可以通过调整 count 参数来减轻源端压力,建议从 1 开始,逐步增加。
  • 对于 KSN 阶段,暂无参数可调整,需要根据源端写请求量来评估是否开启。

性能影响参考数据:源端实例写 QPS 为 15 万左右时,源端 CPU 使用率为 47%,开启 RedisShake 后,源端 CPU 使用率为 91%。

rdb_reader

可以使用 rdb_reader 来从 RDB 文件中读取数据,然后写入目标端。常见于从备份文件中恢复数据。

Scan Reader 实现异地灾备

  • Redis哨兵7.4.3
  • Helm Redis 20.13.4
  • Kubernetes 1.29.0

Kubernetes Redis哨兵部署

Redis部署可以采用容器,虚拟机,阿里云等。对于Redis部署方式没有要求

添加helm源

  1. helm repo add bitnami https://charts.bitnami.com/bitnami

将redis包下载本地

  1. helm pull bitnami/redis --version 20.13.4 --debug

安装redis哨兵

  1. #源端Redis
  2. helm install redis-sentinel -n tools .
  3. #目标端Redis
  4. helm install redis-sentinel-bak -n tools .

修改密码以及storageClass配置,这里我有默认的,我这里就只修改密码

  1. vim redis-sentinel/values.yaml
  2. ## 全局配置
  3. global:
  4. imageRegistry: ""
  5. imagePullSecrets: []
  6. defaultStorageClass: ""
  7. storageClass: ""
  8. security:
  9. allowInsecureImages: false
  10. redis:
  11. password: "123321.."

当源端Redis和目标Redis安装完毕后,我们这里看下Redis Pod和SVC状态

  • redis-sentinel-node 为源端
  • redis-sentinel-bak-node 为目标端
  1. root@k8s-master-01:~/redis/helm/redis-sentinel# kubectl get pod,svc -n tools|grep redis
  2. pod/redis-sentinel-bak-node-0 3/3 Running 0 113s
  3. pod/redis-sentinel-bak-node-1 3/3 Running 0 85s
  4. pod/redis-sentinel-bak-node-2 3/3 Running 0 62s
  5. pod/redis-sentinel-node-0 3/3 Running 3 (21h ago) 4d1h
  6. pod/redis-sentinel-node-1 3/3 Running 3 (21h ago) 4d1h
  7. pod/redis-sentinel-node-2 3/3 Running 0 21h
  8. service/redis-sentinel NodePort 10.96.1.143 <none> 6379:31803/TCP,26379:30295/TCP 4d1h
  9. service/redis-sentinel-bak ClusterIP 10.96.1.220 <none> 6379/TCP,26379/TCP 113s
  10. service/redis-sentinel-bak-headless ClusterIP None <none> 6379/TCP,26379/TCP 113s
  11. service/redis-sentinel-bak-metrics ClusterIP 10.96.0.189 <none> 9121/TCP 113s
  12. service/redis-sentinel-headless ClusterIP None <none> 6379/TCP,26379/TCP 4d1h
  13. service/redis-sentinel-metrics ClusterIP 10.96.3.148 <none> 9121/TCP 4d1h

镜像如果出现问题,可以尝试使用代理加速dockerproxy.frps.fun

修改configmap配置文件

只需要修改Redis源端的缓冲区配置

  1. client-output-buffer-limit replica 0 0 0
  • replica
    该配置项针对复制缓冲区
  • 512mb
    将缓冲区大小的上限设为512M
  • 128mb和60
    若连续60s内写入量>128M,也会触发缓冲区溢出
    这设置何用?
    假设一条写命令数据是1KB,则复制缓冲区可积压512K条(512MB/1KB = 512K)写命令。
    M在全量复制期间,可承受写命令速率上限=2000条/s(128MB/1KB/60≈2000)。
    这就得到一种方案,设置复制缓冲区大小时:
  • 根据写命令数据的大小 && 实际负载情况(即写命令速率),估计缓冲区中会积压的写命令数据量
  • 再和所设置的复制缓冲区大小比较,判断设置的缓冲区是否够支撑积压的写命令数据量
    由于M复制缓冲区的内存开销,会是每个R客户端输出缓冲区占用内存的总和。若集群中的R很多,M内存开销就很大。所以还得控制和M连接的R个数,不要使用大规模主从集群。

这里我直接不限制,设置为0 0 0。生产环境需要根据业务实际情况填写

  1. root@k8s-master-01:~# kubectl get cm -n tools|grep configuration
  2. redis-sentinel-bak-configuration 5 16m
  3. redis-sentinel-configuration 5 4d1h

编辑configmap

  1. root@k8s-master-01:~# kubectl edit cm -n tools redis-sentinel-configuration

在replica.conf下添加

  1. replica.conf: |-
  2. dir /data
  3. # User-supplied replica configuration:
  4. rename-command FLUSHDB ""
  5. rename-command FLUSHALL ""
  6. # End of replica configuration
  7. client-output-buffer-limit replica 0 0 0

重启Redis

  1. root@k8s-master-01:~# kubectl get pod -n tools|grep sentinel|grep -v bak|awk -F "[ ]+" '{print $1}'|xargs kubectl delete pod -n tools
  2. #输出日志
  3. pod "redis-sentinel-node-0" deleted
  4. pod "redis-sentinel-node-1" deleted
  5. pod "redis-sentinel-node-2" deleted

进入容器查看Redis哨兵状态

  1. root@k8s-master-01:~# kubectl exec -it -n tools redis-sentinel-node-0 bash

执行info replication

  1. 127.0.0.1:6379> auth 123321 #根据我们设置的密码登录
  2. 127.0.0.1:6379> info replication
  3. # Replication
  4. role:master
  5. connected_slaves:2
  6. slave0:ip=redis-sentinel-node-1.redis-sentinel-headless.tools.svc.cluster.local,port=6379,state=online,offset=268257,lag=1
  7. slave1:ip=redis-sentinel-node-2.redis-sentinel-headless.tools.svc.cluster.local,port=6379,state=online,offset=268257,lag=0
  8. master_failover_state:no-failover
  9. master_replid:b3528d84ce8f64492822540e1d314cb3ce513735
  10. master_replid2:0000000000000000000000000000000000000000
  11. master_repl_offset:268257
  12. second_repl_offset:-1
  13. repl_backlog_active:1
  14. repl_backlog_size:1048576
  15. repl_backlog_first_byte_offset:1
  16. repl_backlog_histlen:268257

Kubernetes部署RedisShake

官方作者没有出Docker镜像,我们这边直接使用作者的Dockerfile自行打包

  1. git clone https://github.com/tair-opensource/RedisShake.git
  2. cd RedisShake/

打包镜像

  1. docker build -t test:v1 .

设置标签

  1. docker tag test:v1 abcdocker9/redisshake:4.4.1

推送Docker hub

  1. docker push abcdocker9/redisshake:tagname

配置文件说明

sync_reader 配置(源端Redis同步设置)

参数 类型 默认值 说明
cluster bool false 源端是否为Redis集群模式
address string "127.0.0.1:6379" 集群模式下可指定任意节点地址;主从模式需使用主/从节点地址‌
username string "" ACL未启用时留空‌
password string "" 认证需求时留空‌
tls bool false 启用TLS加密传输‌
sync_rdb bool true 是否同步RDB快照数据‌
sync_aof bool true 是否同步AOF日志数据‌
prefer_replica bool false 优先从副本节点同步‌
try_diskless bool false 源端启用repl-diskless-sync时设为true

redis_writer 配置(目标端写入设置)

参数 类型 默认值 说明
cluster bool false 目标端是否为Redis集群‌
address string "127.0.0.1:6380" 集群模式下可指定任意节点地址‌
username string "" ACL未启用时留空‌
password string "" 无认证需求时留空‌
tls bool false 启用TLS加密传输‌
off_reply bool false 关闭服务端响应(提升性能)‌

filter 配置(数据过滤规则)

参数 类型 默认值 说明
allow_keys list [] 白名单键名列表‌
allow_key_prefix list [] 键名前缀白名单‌
block_keys list [] 黑名单键名列表‌
block_key_prefix list [] 键名前缀黑名单‌
function string "" 自定义过滤脚本路径‌

advanced 配置(高级参数)

参数 类型 默认值 说明
ncpu int 0 使用CPU核心数(0=自动检测)‌
log_level string "info" 日志级别(debug/info/warn)‌
pipeline_count_limit int 1024 流水线操作最大并发数‌
aws_psync string "" AWS特殊同步协议配置‌

module 配置(模块兼容性)

参数 类型 默认值 说明
target_mbbloom_version int 20603 Tair模块兼容版本号‌

创建ConfigMap

ConfigMap里面需要配置源端地址以及目标地址

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: redis-shake-config
  5. namespace: tools
  6. data:
  7. shake_sync_env.toml: |
  8. [sync_reader]
  9. sync_mode = true
  10. cluster = false
  11. address = "127.0.0.1:6379" #修改为redis-sentinel.tools.svc.cluster.local
  12. username = ""
  13. password = "123321" #设置Redis密码
  14. tls = false
  15. sync_rdb = true
  16. sync_aof = true
  17. prefer_replica = false
  18. try_diskless = false
  19. [redis_writer]
  20. cluster = false
  21. address = "127.0.0.1:6380" #修改为redis-sentinel-bak.tools.svc.cluster.local
  22. username = ""
  23. password = "123321" #设置Redis密码
  24. tls = false
  25. off_reply = false
  26. [filter]
  27. allow_keys = []
  28. allow_key_prefix = []
  29. allow_key_suffix = []
  30. allow_key_regex = []
  31. block_keys = []
  32. block_key_prefix = []
  33. block_key_suffix = []
  34. block_key_regex = []
  35. allow_db = []
  36. block_db = []
  37. allow_command = []
  38. block_command = []
  39. allow_command_group = []
  40. block_command_group = []
  41. function = ""
  42. [advanced]
  43. dir = "data"
  44. ncpu = 0
  45. pprof_port = 0
  46. status_port = 0
  47. log_file = "shake.log"
  48. log_level = "info"
  49. log_interval = 5
  50. log_rotation = true
  51. log_max_size = 512
  52. log_max_age = 7
  53. log_max_backups = 3
  54. log_compress = true
  55. rdb_restore_command_behavior = "panic"
  56. pipeline_count_limit = 1024
  57. target_redis_client_max_querybuf_len = 1073741824
  58. target_redis_proto_max_bulk_len = 512000000
  59. aws_psync = ""
  60. empty_db_before_sync = false
  61. [module]
  62. target_mbbloom_version = 20603

创建Deployment

代理地址docker pull dockerproxy.frps.fun/abcdocker9/redisshake:4.4.1
官方地址abcdocker9/redisshake:4.4.1

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: redis-shake
  5. namespace: tools
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: redis-shake # 必须与template中的labels完全匹配
  10. template:
  11. metadata:
  12. labels:
  13. app: redis-shake # 必须包含selector中定义的所有标签
  14. spec:
  15. containers:
  16. - name: redis-shake
  17. image: dockerproxy.frps.fun/abcdocker9/redisshake:4.4.1
  18. env:
  19. - name: SYNC
  20. value: "true" # 必须设置为true或false
  21. volumeMounts:
  22. - name: config-volume
  23. mountPath: /app/shake_sync_env.toml
  24. subPath: shake_sync_env.toml
  25. volumes:
  26. - name: config-volume
  27. configMap:
  28. name: redis-shake-config

创建完毕后,我们查看Pod状态以及启动日志

  1. root@k8s-master-01:~/redis/redis-shake# kubectl get pod -n tools
  2. NAME READY STATUS RESTARTS AGE
  3. blackbox-exporter-7b5545fd5-h6k29 1/1 Running 3 (27h ago) 7d16h
  4. categraf-snmp-69f6d68bc7-trjt8 1/1 Running 3 (27h ago) 7d16h
  5. dnsmgr-web-76f6b675fc-xjnxl 1/1 Running 0 27h
  6. excalidraw-9587f9469-b6srm 1/1 Running 1 (27h ago) 4d11h
  7. grafana-6bd875d986-28ndq 1/1 Running 1 (27h ago) 27h
  8. node-exporter-b2q6c 1/1 Running 5 (27h ago) 14d
  9. node-exporter-d2qdv 1/1 Running 7 (27h ago) 14d
  10. node-exporter-mjlxr 1/1 Running 6 (27h ago) 14d
  11. node-exporter-nhktv 1/1 Running 5 (27h ago) 14d
  12. node-exporter-s67cl 1/1 Running 7 (27h ago) 14d
  13. node-exporter-t4jh6 1/1 Running 6 (27h ago) 14d
  14. prometheus-58d5674548-nzmqd 1/1 Running 0 27h
  15. redis-sentinel-bak-node-0 3/3 Running 0 6h36m
  16. redis-sentinel-bak-node-1 3/3 Running 0 6h35m
  17. redis-sentinel-bak-node-2 3/3 Running 0 6h35m
  18. redis-sentinel-node-0 3/3 Running 0 6h16m
  19. redis-sentinel-node-1 3/3 Running 0 6h15m
  20. redis-sentinel-node-2 3/3 Running 0 6h15m
  21. redis-shake-7dc486f775-zl4fm 1/1 Running 2 (36s ago) 40s
  22. root@k8s-master-01:~/redis/redis-shake# kubectl logs -f -n tools redis-shake-7dc486f775-zl4fm
  23. 2025-07-22 15:42:21 INF load config from file: shake_sync_env.toml
  24. 2025-07-22 15:42:21 INF log_level: [info], log_file: [/app/data/shake.log]
  25. 2025-07-22 15:42:21 INF changed work dir. dir=[/app/data]
  26. 2025-07-22 15:42:21 INF GOMAXPROCS defaults to the value of runtime.NumCPU [8]
  27. 2025-07-22 15:42:21 INF not set pprof port
  28. 2025-07-22 15:42:21 INF create SyncStandaloneReader
  29. 2025-07-22 15:42:21 INF * address: redis-sentinel.tools.svc.cluster.local:6379
  30. 2025-07-22 15:42:21 INF * username:
  31. 2025-07-22 15:42:21 INF * password: ********
  32. 2025-07-22 15:42:21 INF * tls: false
  33. 2025-07-22 15:42:21 INF create RedisStandaloneWriter
  34. 2025-07-22 15:42:21 INF * address: redis-sentinel-bak.tools.svc.cluster.local:6379
  35. 2025-07-22 15:42:21 INF * username:
  36. 2025-07-22 15:42:21 INF * password: ********
  37. 2025-07-22 15:42:21 INF * tls: false
  38. 2025-07-22 15:42:21 INF start syncing...
  39. 2025-07-22 15:42:21 INF [reader_redis-sentinel.tools.svc.cluster.local_6379] source db is not doing bgsave! continue.
  40. 2025-07-22 15:42:26 INF read_count=[2788], read_ops=[0.00], write_count=[2788], write_ops=[0.00], syncing aof, diff=[0]
  41. 2025-07-22 15:42:31 INF read_count=[2788], read_ops=[557.55], write_count=[2788], write_ops=[557.55], syncing aof, diff=[0]
  42. 2025-07-22 15:42:36 INF read_count=[2788], read_ops=[0.00], write_count=[2788], write_ops=[0.00], syncing aof, diff=[0]
  43. 2025-07-22 15:42:41 INF read_count=[2788], read_ops=[0.00], write_count=[2788], write_ops=[0.00], syncing aof, diff=[0]
  44. 2025-07-22 15:42:46 INF read_count=[2788], read_ops=[0.00], write_count=[2788], write_ops=[0.00], syncing aof, diff=[0]
  45. 2025-07-22 15:42:51 INF read_count=[2788], read_ops=[0.00], write_count=[2788], write_ops=[0.00], syncing aof, diff=[0]

Kubernetes部署RedisShake实现Redis哨兵异地灾备

模拟数据写入

手动到源端Redis写入数据

  1. root@k8s-master-01:~/redis/redis-shake# kubectl exec -it -n tools redis-sentinel-node-0 sh
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. Defaulted container "redis" out of: redis, sentinel, metrics
  4. $ redis-cli
  5. 127.0.0.1:6379> auth [密码]
  6. OK
  7. 127.0.0.1:6379> set abcdocker i4t
  8. OK
  9. 127.0.0.1:6379>

接下来到目标端查看数据

  1. root@k8s-master-01:~/redis/redis-shake# kubectl exec -it -n tools redis-sentinel-bak-node-0 sh
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. Defaulted container "redis" out of: redis, sentinel, metrics
  4. $ redis-cli
  5. 127.0.0.1:6379> auth [密码]
  6. OK
  7. 127.0.0.1:6379> get abcdocker
  8. "i4t"
  9. 127.0.0.1:6379>

正常监听日志
Kubernetes部署RedisShake实现Redis哨兵异地灾备

常见问题

RedisShake 运行状态日志说明

开启同步时,输出Debug日志,对应参数解释如下

  • read_count # 读取数量
  • read_ops # 读取qps
  • write_count # 写入数量
  • wirte_ops # 写入qps
  • diff # 已读取数据还未写入
  • syncing aof # 使用aof同步

全量是RDB文件,增量是aof数据流,RedisShake会接受全量和增量将其暂存到磁盘上。

当redis-share出现read: connection reset by peer

  1. #完整日志如下
  2. ERR read tcp 192.168.1.1:52646->10.1.1.1:6379: read: connection reset by peer
  3. RedisShake/internal/reader/sync_standalone_reader.go:457 -> (*syncStandaloneReader).receiveAOF()
  4. runtime/asm_amd64.s:1650 -> goexit()

解决办法

  1. #将平台参数值调大,具体大小还是要根据实际业务情况
  2. client-output-buffer-limit replica 0 0 0
  • replica
    该配置项针对复制缓冲区
  • 512mb
    将缓冲区大小的上限设为512M
  • 128mb和60
    若连续60s内写入量>128M,也会触发缓冲区溢出
    这设置何用?
    假设一条写命令数据是1KB,则复制缓冲区可积压512K条(512MB/1KB = 512K)写命令。
    M在全量复制期间,可承受写命令速率上限=2000条/s(128MB/1KB/60≈2000)。
    这就得到一种方案,设置复制缓冲区大小时:
  • 根据写命令数据的大小 && 实际负载情况(即写命令速率),估计缓冲区中会积压的写命令数据量
  • 再和所设置的复制缓冲区大小比较,判断设置的缓冲区是否够支撑积压的写命令数据量
    由于M复制缓冲区的内存开销,会是每个R客户端输出缓冲区占用内存的总和。若集群中的R很多,M内存开销就很大。所以还得控制和M连接的R个数,不要使用大规模主从集群。

断点续传

支持断开后按offset恢复,无需额外配置

缓存日志及Log日志存储路径

  • redis-shake 默认目录为/apps
  • data 存储日志以及AOF文件
  • data/shake.log 运行状态一直,可以看到redis-shake运行状态
  1. root@k8s-master-01:~/redis/redis-shake# kubectl exec -it -n tools redis-shake-7dc486f775-zl4fm sh
  2. /app # ls
  3. data entrypoint.sh redis-shake shake_scan_env.toml shake_sync_env.toml
  4. /app # ls data/
  5. pid.lockfile shake.log
  6. reader_redis-sentinel.tools.svc.cluster.local_6379
  7. /app # ls data/reader_redis-sentinel.tools.svc.cluster.local_6379/
  8. 0.aof
  9. /app # tail data/shake.log
  10. {"level":"info","time":"2025-07-22T16:00:56Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  11. {"level":"info","time":"2025-07-22T16:01:01Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  12. {"level":"info","time":"2025-07-22T16:01:06Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  13. {"level":"info","time":"2025-07-22T16:01:11Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  14. {"level":"info","time":"2025-07-22T16:01:16Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  15. {"level":"info","time":"2025-07-22T16:01:21Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  16. {"level":"info","time":"2025-07-22T16:01:26Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  17. {"level":"info","time":"2025-07-22T16:01:31Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  18. {"level":"info","time":"2025-07-22T16:01:36Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}
  19. {"level":"info","time":"2025-07-22T16:01:41Z","message":"read_count=[2790], read_ops=[0.00], write_count=[2790], write_ops=[0.00], syncing aof, diff=[0]"}

注意事项

  • 长时间无同步流量导致的,Shake 确实缺乏保活机制,在长时间无同步是可能会被杀掉 (Pod不存在此问题)
  • 集群的writer速度太快。可能存在超时导致失败情况,需要定时日志监控
  • 目前Redis-Shake无法检测灾备状态,短暂需要人为操作,用于迁移工具实际作用更大