主从切换后数据不一致是必须验证的确定性风险,需通过业务核心key存在性与TTL、集合成员一致性、有序集合score+member全字段匹配三维度对账,禁用KEYS等阻塞命令,注意Lua脚本执行环境差异。

主从切换后数据不一致不是小概率事件,而是必须验证的确定性风险——尤其在金融、订单类场景,不能依赖“应该没问题”。
为什么 INFO replication 和 redis-cli --latency 不能代替数据对账
它们只反映连接状态和延迟,完全不校验实际数据。常见错误是切完主从就跑 redis-cli -h new-master info replication 看 role:master 就认为 OK。但:
• 旧 master 上未同步到 slave 的写入(如网络分区期间)会永久丢失
• slave 在切换前已落后但未触发 min-slaves-to-write 保护,导致部分 key 缺失
• AOF 重写或 RDB 加载过程中的截断可能造成中间态数据不完整
对账脚本必须覆盖的三个关键维度
只比 key 数量或总内存占用毫无意义。真实业务中要盯住:
• 业务核心 key 的存在性与 TTL:比如用户余额 balance:1001 是否还在,TTL 是否被意外重置为永不过期
• 集合类结构的成员一致性:用 SMEMBERS order:20240501 比对两边返回的元素是否完全相同(注意顺序无关,需排序后比对)
• 有序集合的 score + member 组合:ZRANGE leaderboard 0 -1 WITHSCORES 必须全字段匹配,score 微小浮点误差也要告警
如何避免对账过程本身影响线上服务
直接在生产节点上执行全量 KEYS * 或 SCAN 扫描会阻塞主线程,尤其当 key 数量 > 100 万时:
• 用 redis-cli --scan --pattern "balance:*" 替代 KEYS,降低单次扫描压力
• 对账脚本必须加 --read-only 参数连新 master,防止误写
• 设置 CLIENT SETNAME audit-check-20240501,便于在 CLIENT LIST 中快速识别并 kill 掉异常长连接
• 不要一次性拉取全部数据到内存比对;改用流式处理:逐个 GET / SMEMBERS,发现差异立即记录并继续
最容易被忽略的冷门坑:Lua 脚本执行结果不一致
如果业务用了 EVAL 做原子计数或条件更新,切换后脚本返回值可能不同:
• 新 master 的 Lua 环境时间戳(redis.call("TIME"))和旧 master 不同,影响依赖时间的逻辑
• SCRIPT LOAD 后的 SHA1 在不同实例间不保证自动同步,需确认 SCRIPT EXISTS 返回 true 再执行
• 集群模式下若用 redis-cli -c 连接,EVAL 的 key hash tag 若没对齐 slot,可能路由到错误节点导致结果错乱
真正难的不是写脚本,而是定义清楚“哪些 key 必须 100% 一致”以及“允许哪些字段有可控偏差”。比如优惠券剩余数量允许 ±1,但用户账户余额必须严格相等——这个边界得业务方拍板,运维只负责把差异量化出来。


















