Redis 4.0不支持主主模式,run_id仅用于标识主节点身份以判断是否可增量同步,而非防冲突;从节点执行replicaof后立即只读,写操作均被拦截。

Redis 4.0 并不支持主主(multi-master)模式,所谓“主主冲突”在 Redis 原生架构中根本不存在——它从设计上就禁止从节点写入,replicaof 建立的是严格单向复制链路。你看到的“数据乱序”,实际是主从同步延迟、断线重连时 run_id 不匹配触发全量复制,或客户端误连从节点执行写操作导致的脏数据,并非主主冲突。
为什么 run_id 不是用来防主主,而是防“认错主”
run_id 是每个 Redis 实例启动时生成的 40 位十六进制字符串,保存在 info server 的 run_id 字段里。它的唯一作用是:让从节点确认“我现在连的,是不是上次同步过的那个主节点”。
- 如果从节点断线后重连,发送
PSYNC <run_id><offset></offset></run_id>,而主节点发现run_id不匹配,说明主节点已重启或从节点连错了实例 → 只能全量复制 - 如果
run_id匹配,但offset超出复制积压缓冲区范围 → 仍需全量复制 - 只有
run_id匹配且offset有效 → 才走部分复制(增量补发命令)
它不参与任何“冲突检测”或“写权限仲裁”,因为 Redis 根本没给从节点写权限。
replicaof 命令执行后,从节点立刻拒绝写操作
一旦执行 replicaof 192.168.150.101 7001,该节点会立即进入只读状态:
- 所有写命令如
SET、DEL、INCR都返回错误:READONLY You can't write against a read only replica. - 这个限制由
server.masterhost != NULL触发,在命令执行前就被拦截,不依赖网络或配置刷新 - 即使你用
CONFIG SET临时改slave-read-only no,也只影响当前连接,且下次replicaof或重启即失效
真正导致“看起来像主主乱序”的三个常见原因
这些才是你在生产环境里大概率遇到的问题:
- 客户端直连从节点并绕过只读检查(比如用低版本 Jedis、未设
readFrom=SLAVE),手动发SET→ 数据只存在从节点,主节点无感知,后续主从切换后丢失 - 主节点故障期间,哨兵提升从节点为新主,但旧主恢复后未被自动降级,变成“双主” → 此时两个节点都接受写入,数据彻底分裂(必须人工介入,删掉一个的数据或重做全量同步)
- 应用层用了带本地缓存的 SDK(如某些 Spring Cache 实现),写完主节点后没清从节点缓存,读从节点时命中过期缓存 → 表现为“读到旧值”,不是 Redis 层乱序
如何验证当前主从是否真的“身份一致”
别只看 INFO REPLICATION,要交叉比对:
- 在从节点执行:
redis-cli -p 7002 INFO REPLICATION | grep -E "(master_host|master_port|master_link_status|master_replid)" - 在主节点执行:
redis-cli -p 7001 INFO SERVER | grep run_id - 再回到从节点,执行:
redis-cli -p 7002 DEBUG REPLICA-OF 192.168.150.101 7001(注意:这是调试命令,仅限排查,不要在生产用)→ 它会强制重置复制状态并重新比对run_id
最关键的细节:只要 master_replid 和主节点的 run_id 对不上,哪怕 IP 端口完全正确,复制就不可能进入部分同步阶段——这个判断发生在 TCP 连接建立后的第一条 PSYNC 命令响应里,没有商量余地。


















