确认脑裂后,旧主节点内存中保留着未同步的增量数据,关键依据是其replication offset高于新主节点;需通过redis-cli获取各节点offset比对,并用--rdb导出快照或解析AOF提取故障期间写入。

确认脑裂后哪些节点还保留着“未同步的增量数据”
脑裂刚恢复时,旧主节点(原 master)很可能已被降级为 slave,但它的内存里还存着故障期间接收却未同步到新主的数据——这些就是抢救对象。关键不是看“谁是 master”,而是看 replication offset:它代表该节点当前已执行的写命令序号。只要旧主的 offset 高于新主的 offset,就说明它有新主没有的增量。
逐个登录所有节点执行:redis-cli -h 192.168.1.101 -p 6379 INFO replication | grep -E "role|offset"
- 找到角色为
master且connected_slaves: 0的节点 → 很可能是隔离期间的“幽灵主” - 对比各节点的
master_repl_offset(主节点)或slave_repl_offset(从节点),找出 offset 最高的那个 - 特别注意:如果旧主已被强制降级为 slave,它的
slave_repl_offset可能仍高于新主的master_repl_offset,这就是数据残留证据
用 redis-rdb-tools 提取 RDB 中的增量键值对
RDB 文件本身不记录增量时间线,但如果你在脑裂前启用了 save 配置或开启了 AOF,RDB 可能包含部分未同步数据;更可靠的是直接从内存 dump —— 但生产环境通常禁用 DEBUG OBJECT 或 CONFIG SET。稳妥做法是:在旧主节点仍存活、未被强制全量同步前,用 redis-cli --rdb 导出当前内存快照:
redis-cli -h 192.168.1.102 -p 6379 --rdb /tmp/old-master-dump.rdb
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 这个命令会触发一次阻塞式 RDB 生成(不依赖配置中的
save规则),内容反映当前内存状态 - 用
redis-rdb-tools解析:rdt --command json /tmp/old-master-dump.rdb | jq 'select(.type=="hash" or .type=="string")',筛选出非系统键 - 重点比对 key 的 TTL 和最后访问时间(如果应用层写入时带了
EXPIREAT),可辅助判断是否为脑裂期间写入
用 AOF 文件定位并提取故障窗口内的写命令
如果旧主启用了 AOF(appendonly yes),且使用 appendfsync everysec 或 always,AOF 文件末尾大概率保留了脑裂期间的写命令。注意:AOF 是追加日志,但默认不带时间戳,需靠上下文推断窗口。
- 先查旧主的 AOF 文件最后修改时间:
stat /var/lib/redis/appendonly.aof | grep Modify,与网络分区起止时间交叉比对 - 用
redis-check-aof --fix确保文件结构完整,再用tail -n +10000 /var/lib/redis/appendonly.aof | head -n 5000截取末段(根据分区时长估算行数) - 过滤出写操作:
grep -E "^(SET|INCR|HSET|LPUSH|ZADD) " appendonly.aof.tail,人工确认是否属于业务关键操作 - ⚠️ 警惕:若 AOF 开启了
aof-rewrite,重写后的文件会丢弃旧命令,此时只能依赖 RDB 或应用层 binlog 补偿
把抢救出的数据安全合并进新主集群
不能直接 RESTORE 或 SET 到新主——可能覆盖已有更新、破坏 slot 分配。正确做法是:按 key 所属 slot,定向写入对应节点,并跳过已存在且更新的版本。
- 用
redis-cli --cluster check确认当前 slot 分布,再对每个抢救出的 key 执行:redis-cli -c -h new-master-ip -p 6379 CLUSTER KEYSLOT keyname,获取目标节点 - 写入前加条件判断:
redis-cli -h target-node-ip -p 6379 EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then return redis.call('SET', KEYS[1], ARGV[1]) else return 0 end" 1 keyname value - 若业务允许最终一致,优先走异步补偿通道(如发 Kafka 消息触发下游重算),避免阻塞线上流量
真正难的不是提取数据,而是判断哪些 key 值该保留、哪些该丢弃——比如同一订单号在两个分区分别生成了不同状态,这种冲突必须交由业务规则裁决,Redis 层无法自动解决。

















