一个分片的主库和从库同时挂了怎么办?这比「主库挂了从库接手」严重得多:那一片数据在集群里已经没有副本了。这篇复现这个最坏情形,看三种结局:数据在磁盘上→重启找回;没有持久化→集群「恢复正常」却悄悄丢了三分之一的数据;放弃数据→用 fix 强行让集群可用。
被杀:主 7560 + 从 7564;幸存节点上 cluster_state 变化(相对 kill 的秒数):{'ok': 0.0, 'fail': 4.99}
在幸存主库 7561 上写它自己负责的槽里的 key: CLUSTERDOWN The cluster is down 读 key: CLUSTERDOWN The cluster is down
向幸存主库请求已丢失分片的 key k:3: CLUSTERDOWN The cluster is down
只重启被杀的主库(AOF 加载):3.18 s 后整个集群 cluster_state = ok
数据校验(30000 个 key):读不到/值不对 0 个,出错 0 个杀掉分片 X 的主库和从库后,幸存节点在 5.0 s 后把 cluster_state 置为 fail。之后无论读写,哪怕是完全属于幸存分片的 key,都会得到 CLUSTERDOWN The cluster is down:默认 cluster-require-full-coverage yes 要求 16384 个槽都有主库,少一个就全体拒绝服务。
恢复:只重启被杀的主库(nodes.conf 在,AOF 在):3.2 s 后整个集群回到 ok,30000 个 key 校验丢失 0 个(这里 AOF 用了 appendfsync always;默认 everysec 下崩溃时可能丢最近约 1 秒——这一点本文没有实测)。
重启主库后 2.05 s cluster_state = ok(nodes.conf 还在,槽位归属恢复) 数据校验(30000 个 key):读不到 9998 个(33.3%),出错 0 个——集群「恢复正常」,但这一片数据没了
没有 AOF、没有 RDB 时,重启的主库带着旧的 nodes.conf(槽位归属)上线,但数据是空的。集群 2.1 s 就回到 ok,看起来完全正常——但读 30000 个 key,9998 个读不到(33.3%,恰好是那个分片)。没有任何告警:cluster_state 是 ok,只是那一片数据没有了。这也是集群里「主库必须有持久化,或者至少有从库」的原因:从库是第二份副本,持久化是第三份。
幸存节点 cluster_state 变化:{'ok': 0.0};CLUSTER INFO 里 cluster_slots_ok / fail: 10923 / 5461 cluster_state = ok
写幸存分片的 key: OK 读: w
请求已丢失分片里的 key k:3: MOVED 2036 127.0.0.1:7580cluster-require-full-coverage no 让集群在有槽没人负责时仍然工作:幸存节点 cluster_state = ok,cluster_slots_ok / cluster_slots_fail = 10923 / 5461,写幸存分片的 key 成功。请求丢失分片的 key,幸存节点回 MOVED 指向那个已经死掉的主库——客户端会连不上、超时。这是「部分可用」与「全体可用」的取舍。
fix 输出(关键行):
[OK] 20002 keys in 2 masters.
[OK] All nodes agree about slots configuration.
[ERR] Not all 16384 slots are covered by nodes.
>>> Fixing slots coverage...
The following uncovered slots have no keys across the cluster:
Fix these slots by covering with a random node? (type 'yes' to accept): >>> Covering slot 576 with 127.0.0.1:7582
>>> Covering slot 1531 with 127.0.0.1:7582
>>> Covering slot 2691 with 127.0.0.1:7582
>>> Covering slot 1551 with 127.0.0.1:7582
>>> Covering slot 4055 with 127.0.0.1:7582
之后 cluster_state = ok cluster_slots_ok = 16384
数据校验(前 6000 个 key):读不到 2008 个,出错 1 个(那一片数据永久丢失,槽位被分配给了存活的主库)如果那个分片确实回不来了,又想让集群恢复完整,redis-cli --cluster fix 可以把没人负责的槽分给存活的主库。它对「有不可达主库」的情形要求额外的 --cluster-fix-with-unreachable-masters 选项,并且提示这可能导致数据丢失;确认后逐个槽位 Covering slot … with 127.0.0.1:7582。结果:cluster_state 回到 ok,cluster_slots_ok = 16384,但那片数据永久丢了(前 6000 个 key 里 2008 个读不到)。