1. 这篇文章真正要解决的问题
如果你负责过 Redis 生产环境,或者用 Redis 搭过主从加哨兵的架构,大概率碰到过一个非常诡异的现象:
主节点明明还在运行,日志里也没有出现崩溃,但业务却突然写入失败,或者部分数据悄悄丢了。等你去查监控,发现“不分青红皂白”地出现了一个新的主节点,而原来的老主节点变成了一台孤立的“光杆司令”。
更让人懵的是,当网络恢复后,老主节点仿佛被“降级”了一样,之前那几分钟写入的数据全部没了。你翻遍业务日志,没有发现任何显式的报错,数据就是没了。
这就是 Redis 脑裂(Split Brain)的典型表现。
很多人第一次听到“Redis 脑裂”,第一反应是:是不是 Redis 有 Bug?是不是哨兵(Sentinel)不靠谱?是不是主从复制出了问题?
这里先给一个明确判断:Redis 脑裂不是 Redis 本身的 Bug,也不是哨兵的随机抽风,而是分布式系统中“网络分区 (Network Partition) + 主备切换机制”共同作用下的必然结果。
换句话说,只要你用了 Redis 主从 + 哨兵模式,又没有对写入方做任何保护,脑裂就随时可能发生。这不是概率问题,而是时间问题。
这篇文章我想把 Redis 脑裂这件事彻底讲透。我会从主从架构和哨兵的原理讲起,带你看清楚脑裂发生的完整链路,然后给你可以直接照做的排查命令、防脑裂配置和最佳实践。
如果你正在用 Redis 做缓存、做分布式锁,或者准备在生产环境搭建 Redis 高可用集群,这篇文章建议先收藏。脑裂等出问题时再学,代价往往已经不太小了。
2. 什么是脑裂:从现实场景理解分布式系统的“人格分裂”
脑裂这个术语最早来自医学,指的是连接左右脑半球的胼胝体受损后,左右脑各自为政,人体出现“两个意识”的状态。
在分布式系统里,脑裂的含义类似:一个集群中,因为网络分区、节点假死等原因,原本只有一个 Leader(主节点)的系统里,同时出现了两个或多个节点认为自己是 Leader,继续对外提供服务。
对 Redis 来说,脑裂的直接表现就是:
同一份数据,同时有两个主节点在写。
这里要区分一个概念:Redis 脑裂并不是 Redis 主从复制本身坏了,而是“容错切换决策”和“实际存活状态”之间出现了不一致。
2.1 为什么会出现两个主节点
Redis 主从模式下,正常情况下只有一个 master,所有写操作都走 master,从节点(slave/replica)只同步数据,不对外提供写服务。
当 master 出现故障时,哨兵会发起故障转移(failover),从从节点里选出一个新的 master。这个过程本身没有错。
但问题是:哨兵是怎么判断 master 故障的?
答案是“主观下线”和“客观下线”。这部分后面细讲,简单说就是:如果 master 和哨兵之间的网络断了,但 master 本身还在运行,比如还在接收客户端的写请求,那么哨兵会主观认为 master 挂了,然后发起故障转移,选出一个新 master。
于是:
- 老 master 还在接受写入。
- 新 master 也在接受写入。
- 两边同时写,数据分叉。
这就是脑裂。
2.2 Redis 脑裂的本质是 CAP 的取舍
要真正理解脑裂,不能只看 Redis 配置,还要理解 CAP 理论。
CAP 理论说的是:一个分布式系统,在网络分区发生时(P),你只能在一致性(C)和可用性(A)之间二选一。
Redis 做主从切换,追求的是高可用(A):当主节点失联时,尽快选出新主,让业务不中断。
但代价是什么?是可能牺牲一致性(C):在极端情况下,旧主节点并没有真正宕机,它只是和哨兵网络断了,用户写入的数据没有同步到新主。
所以更准确的说法是:Redis 脑裂不是故障,而是 Redis 在“网络分区+高可用切换”场景下,默认选择了“可用性优先”的必然结果。
理解这一点很重要,因为它决定了你不能用“加几个哨兵”来解决脑裂,而要从架构设计层面去约束“旧主”的行为。
3. Redis 主从架构与哨兵:脑裂出现前的基础设施
在深入脑裂机制之前,必须先梳理 Redis 主从和哨兵的工作流程。很多人对脑裂的理解模糊,其实是基础概念不牢固。
3.1 主从复制(Master-Slave Replication)
Redis 主从复制的作用,简单说就是把一台 Redis 节点的数据,实时同步到其他节点。
- 主节点(master):处理写请求,把写操作记录到自己的内存,并异步发送给从节点。
- 从节点(replica):只处理读请求,接收主节点的同步数据,保证和主节点最终一致。
主从复制的核心步骤是:
- 从节点向主节点发送
PSYNC命令,请求同步。 - 主节点执行
BGSAVE生成 RDB 快照,同时把新写入的命令记录到复制缓冲区。 - 主节点把 RDB 文件发送给从节点。
- 从节点加载 RDB 文件后,主节点继续把复制缓冲区中的写命令发给从节点。
- 后续主节点每执行一条写命令,都会实时发送给从节点。
注意第 5 步:Redis 的复制默认是异步的。
主节点执行SET key value之后,并不会等待从节点确认“我已经写好了”,而是直接返回给客户端。
这意味着什么?意味着主节点上存在一段“最近写入但还没有同步到从节点”的数据窗口。一旦主节点在这时发生故障或切换,这部分窗口数据就可能会丢失。
3.2 哨兵(Sentinel)如何工作
Sentinel 是 Redis 提供的高可用解决方案,它的职责是:
- 监控所有 Redis 节点的健康状态。
- 当主节点出现问题时,自动执行故障转移,从从节点中选出新的主。
- 把新主节点的信息通知给客户端。
哨兵有几个关键概念:
| 概念 | 解释 |
|---|---|
| 主观下线(SDOWN) | 单个哨兵发现主节点没有在down-after-milliseconds时间内响应,标记为“主观下线” |
| 客观下线(ODOWN) | 多个哨兵(达到 quorum 数量)都认为主节点下线,则标记为“客观下线” |
| 故障转移(Failover) | 客观下线后,哨兵们选出一个 Leader 哨兵,从从节点中选出新主,并修改配置 |
这里就出现了第一个容易被忽略的点:
主观下线只需要一个哨兵就能触发。
它依据的是哨兵和主节点之间的网络通信状态,而不是主节点本身的存活状态。
如果 Redis 主节点所在的服务器只是网络暂时抖动,或者主节点 CPU 负载过高导致无法及时响应 Ping,但主节点本身还在正常运行,哨兵依然会判定它主观下线。
于是后面的事情就顺理成章:
- 哨兵 A 发现主节点 ping 不通,标记主观下线。
- 如果多个哨兵都收不到主节点的响应,达到 quorum,标记客观下线。
- 哨兵触发故障转移,从从节点中选出新主。
而客户端那边呢?如果客户端还连在旧主上,写操作依然会成功。
两个主节点同时工作的局面形成了。
4. Redis 脑裂的完整触发过程:从网络抖动到数据丢失
现在我们把上面的知识串起来,完整走一遍 Redis 脑裂的生命周期。
假设我们有这样一个环境:
- 3 个 Redis 节点:1 个 master、2 个 replica。
- 3 个 Sentinel 实例。
- 业务应用通过哨兵获取主节点地址,连接 Redis。
4.1 第一阶段:网络分区发生
假设 Redis 主节点所在的机器,因为交换机故障或者网络拥塞,和 Sentinel、从节点之间的网络彻底断了。
但这里有个关键细节:**主节点所在的机器本身没有宕机,Redis 进程也没有崩溃。**主节点依然可以接受客户端连接和写入,只是它再也联系不上从节点和哨兵了。
此时其实已经形成一个“网络分区”:
- 分区 A:旧 master + 连接它的客户端。
- 分区 B:哨兵 + 两个从节点 + 通过哨兵路由的客户端。
4.2 第二阶段:哨兵判定主节点下线
哨兵节点每隔sentinel monitor配置的时间间隔,会向主节点发送 Ping。
因为网络断了,哨兵收不到主节点的 Pong 响应,等待超过down-after-milliseconds后,哨兵会把这个主节点标记为sdown(主观下线)。
如果 3 个哨兵都这样认为,并且配置的quorum值小于等于 2,那么主节点被标记为odown(客观下线)。
于是哨兵开始执行故障转移流程。
4.3 第三阶段:选出新主节点
哨兵集群经过投票选出一个 Leader 哨兵,由它执行故障转移:
- 从两个从节点中选出一个,执行
SLAVEOF NO ONE,提升它为新的 master。 - 另一个从节点执行
SLAVEOF new_master_ip new_master_port,变成新主的从节点。 - 哨兵更新自己的配置,通知客户端新的主节点地址。
从这一刻开始,分区 B 中已经有自己的 master 了。
4.4 第四阶段:旧主依然接收写入(脑裂形成)
关键问题来了:在分区 A 中,旧 master 依然活着,依然接收客户端的写请求。
如果客户端没有通过哨兵动态感知主节点变更,而是维护了一个静态的主节点连接,那么客户端写请求还是会打到旧 master 上。
旧 master 接收到SET key value后:
- 它无法把这写命令同步给从节点(因为网络断了)。
- 但它会正常执行,并且告诉客户端“写入成功”。
此时:
- 旧 master 上有最新的数据。
- 新 master 上只有网络断开前同步过的老数据。
两个“主节点”同时接受写请求,数据开始分叉。这就是 Redis 脑裂的完成形态。
4.5 第五阶段:网络恢复和无情的数据丢失
假设网络修复了,旧 master 和哨兵、从节点的连接恢复了。
哨兵发现旧 master 还活着,但此时新 master 已经产生。那么哨兵会强制把旧 master 降级为从节点,并向新 master 发起全量同步(full resync)。
全量同步意味着什么?意味着旧 master 会在同步前清空自己的数据,然后加载新 master 的 RDB 快照。
在脑裂期间,旧 master 上多写入的数据,全部丢失。
这个数据丢失不可恢复,因为它从来没有同步到任何其他节点。
所以你看,整个链路下来,没有任何一个环节是“故意丢数据”的,但最终数据就是丢了。这就是分布式系统的一致性和可用性博弈的代价。
5. 如何判断 Redis 是否发生过脑裂
脑裂发生的时候,业务端不一定有明显报错,数据丢失也常常是“悄悄发生”的。但我们可以通过一些迹象和命令来判断。
5.1 查看哨兵日志
哨兵日志里会有明显的故障转移记录。当你发现以下日志时,说明发生过主备切换:
# 主观下线 +sdown master mymaster 192.168.1.10 6379 # 客观下线 +odown master mymaster 192.168.1.10 6379 #quorum 2/2 # 开始故障转移 +try-failover master mymaster 192.168.1.10 6379 # 选出了新主 +switch-master mymaster 192.168.1.10 6379 192.168.1.11 6379+switch-master后面那行,就是切换前后的主节点地址。看到这一行,就要意识到刚才可能发生过脑裂。
5.2 检查 Redis 节点的角色变化
使用info replication命令,可以查看当前节点的角色信息。
在旧主节点上执行:
redis-cli -p 6379 info replication正常情况下,主节点的role应该是master。如果发生了脑裂且网络已恢复,旧主会被降级为slave,并指向新主。
如果脑裂尚未恢复,你可以看到旧主还是master,但它的connected_slaves计数为 0,说明没有从节点连接它,这就很可疑。
# 旧主节点在脑裂期间的输出 role:master connected_slaves:0 master_replid:xxxxx再看新主节点,能看到它已经有从节点了:
# 新主节点恢复后的输出 role:master connected_slaves:1 slave0:ip=192.168.1.12,port=6379,state=online,offset=12345,lag=05.3 查看命令统计中的延迟和拒绝
如果配置了min-replicas-to-write参数(后面会讲),脑裂期间旧主会拒绝写入。此时通过info stats命令可以看到:
redis-cli -p 6379 info stats | grep rejected sync_rejected_writes:5sync_rejected_writes统计了因为从节点数量不足而被拒绝的写命令数量。一旦这个值大于 0,说明系统曾经触发过写保护。
5.4 客户端侧如何发现
如果你用的是 Lettuce 或 Jedis 客户端,并且配置了哨兵模式,当主节点变更时,客户端会收到重定向通知。
但这里有个容易被忽略的坑:旧主节点只是网络分区,并没有真正宕机;客户端如果保持长连接,它不会主动感知主节点变更。
所以在实际项目中,更可靠的做法是:通过 Redis Sentinel 获取当前主节点地址来建立连接,并监听主节点切换事件。这样在主节点切换时,客户端能重新建立连接。具体的处理逻辑各语言客户端支持不同,落地时要选对 API。
6. 防止 Redis 脑裂后的数据丢失:min-replicas 详解
明白了脑裂的原理,现在要解决实际问题:怎么防止脑裂时的数据丢失。
有人可能会说:那我不用主从、不用哨兵,行不行?当然可以,但这就放弃了高可用。如果你的业务允许短暂停机,单节点 Redis 反而是最简单可靠的方案。
但大多数生产系统需要高可用,所以必须接受“主备切换可能发生”这个现实。在此基础上,我们能做的是:让旧主在失去从节点同步能力时,主动拒绝写入。
这样就算脑裂发生,旧主上也不会产生新数据,网络恢复后降级为从节点,数据不会丢。
这个能力 Redis 早就提供了,就是min-replicas-to-write和min-replicas-max-lag。
6.1 配置项说明
在 Redis 的配置文件中(redis.conf),主节点可以设置两个参数:
# 当主节点拥有的健康的从节点数量小于该值时,停止接受写请求 min-replicas-to-write 1 # 从节点的数据同步延迟超过该值(秒),视为不健康 min-replicas-max-lag 10含义是:
min-replicas-to-write 1:主节点必须至少有一个健康的从节点,才允许接受写请求。min-replicas-max-lag 10:从节点的复制延迟(lag)不能超过 10 秒。如果超过,就认为这个从节点不健康。
两个条件同时满足才允许写。也就是说:
如果健康的从节点数量 < min-replicas-to-write,拒绝写入。回到脑裂场景:
- 网络分区后,旧主无法和从节点通信,从节点 lag 不断增长,超过 10 秒。
- 主节点检查发现“健康从节点数量”变为 0,小于配置的
min-replicas-to-write 1。 - 于是后续的写请求被拒绝,客户端会报错(不是写入超时,而是直接被拒)。
这样,旧主就不会产生新的增量数据。网络恢复后,旧主降级为从节点,数据依然一致,不会丢失。
6.2 动态配置
如果你已经部署了 Redis,可以通过命令动态调整参数,不用重启:
# 登录 Redis 后执行 CONFIG SET min-replicas-to-write 1 CONFIG SET min-replicas-max-lag 10 # 同时写入配置文件,防止重启后失效 CONFIG REWRITE6.3 这两个配置有什么代价
先说清楚:min-replicas-to-write不是没有代价的。
假设你的主节点确实挂了,但是从节点还没有被哨兵提升为新主,这期间客户端写入会失败。相当于用“暂时不可用”换取了“数据不丢失”。
这其实是把 Redis 从“可用性优先”拉向了“一致性优先”。
对缓存场景来说,写入失败问题不大,缓存 miss 后下次再写即可。但对分布式锁、秒杀扣减库存、订单状态更新等强一致场景,写入失败比“写入成功但数据丢失”要好得多,因为前者至少能被业务方感知并重试,后者是无声丢失,排查代价极高。
所以在生产环境,建议这样配置:
| 场景 | 建议 |
|---|---|
| 只做缓存,允许少量数据丢失 | 可以不配置 min-replicas-to-write 或设 0 |
| 缓存 + 数据一致性要求高 | 配置min-replicas-to-write 1 |
| 分布式锁 / 强一致业务 | 必须配置,且要配合 RedLock 等方案做兜底 |
6.4 配置参考示例
以下是一个完整的 redis.conf 主节点相关配置示例,可作为生产环境模板参考:
# 基本主从配置 replica-read-only yes # 脑裂保护 min-replicas-to-write 1 min-replicas-max-lag 107. 完整实践:搭建一个可复现脑裂的 Redis 环境
理解了理论,最好亲手验证一次。下面用一个最小化的本地环境,模拟“主节点网络分区导致脑裂和数据丢失”的过程。
7.1 环境准备
在本地安装 Redis 后,创建三个目录,分别模拟三个节点:
mkdir -p /tmp/redis-lab/{6379,6380,6381}分别创建三个配置文件。
主节点配置 /tmp/redis-lab/6379/redis.conf:
port 6379 daemonize yes dir /tmp/redis-lab/6379 logfile "redis.log" pidfile "/tmp/redis-lab/6379/redis.pid" # 脑裂保护配置 min-replicas-to-write 1 min-replicas-max-lag 10从节点 1 配置 /tmp/redis-lab/6380/redis.conf:
port 6380 daemonize yes dir /tmp/redis-lab/6380 logfile "redis.log" pidfile "/tmp/redis-lab/6380/redis.pid" replicaof 127.0.0.1 6379从节点 2 配置 /tmp/redis-lab/6381/redis.conf:
port 6381 daemonize yes dir /tmp/redis-lab/6381 logfile "redis.log" pidfile "/tmp/redis-lab/6381/redis.pid" replicaof 127.0.0.1 63797.2 启动节点
redis-server /tmp/redis-lab/6379/redis.conf redis-server /tmp/redis-lab/6380/redis.conf redis-server /tmp/redis-lab/6381/redis.conf启动后,在主节点上确认从节点已经连上:
redis-cli -p 6379 info replication预期输出类似:
# Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6380,state=online,offset=14,lag=0 slave1:ip=127.0.0.1,port=6381,state=online,offset=14,lag=07.3 模拟网络分区
为了模拟脑裂,我们不能直接杀掉主节点进程,因为 Redis 主节点如果真正宕机,就不会再接受写请求了。
正确做法是使用 Linux 的iptables规则,只阻断主节点到从节点、哨兵的通信,但保留主节点到客户端的连接。
在真实环境中,网络分区往往就是这么发生的。
# 阻断主节点 6379 访问 6380 和 6381 的端口 iptables -A OUTPUT -p tcp --dport 6380 -j DROP iptables -A OUTPUT -p tcp --dport 6381 -j DROP7.4 观察脑裂保护是否生效
等 10 秒以上(超过 min-replicas-max-lag 设定的 10 秒),让主节点察觉到从节点延迟超限。
此时向主节点写入数据:
redis-cli -p 6379 set name "test-split-brain"预期返回错误:
(error) NOREPLICAS Not enough good replicas to write.这个错误告诉我们:主节点因为健康从节点数量不足,已经拒绝写入。
7.5 模拟未配置保护的后果
现在我们去掉脑裂保护配置,再来一次:
redis-cli -p 6379 CONFIG SET min-replicas-to-write 0 redis-cli -p 6379 CONFIG SET min-replicas-max-lag 0再执行写入:
redis-cli -p 6379 set name "data-without-protection" # 输出 OK这时主节点会返回OK。如果你在真实生产环境不小心出现过这种情况,说明脑裂期间数据已经开始分叉了。
7.6 清理环境
实验结束后,清除防火墙规则,并停止 Redis:
iptables -F redis-cli -p 6379 shutdown nosave redis-cli -p 6380 shutdown nosave redis-cli -p 6381 shutdown nosave这里要额外提醒:iptables -F会清空所有自定义规则,如果在有业务流量的机器上执行要谨慎。建议实验环境使用专用的 namespace 或测试机,生产环境不要直接操作防火墙规则来模拟分区。
这个实验的核心结论是:不配置 min-replicas-to-write,主节点会傻傻地持续接受写入,直到数据被覆盖;配置了之后,主节点在失去从节点连接时会主动“暂停写入”,宁可报错也不让数据分裂。
8. 生产环境 Redis 脑裂的常见问题与排查思路
在实际生产环境,脑裂的排查往往比模拟复杂得多。这里整理几个高频问题和对应排查路径。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 业务突然大批量报 NOREPLICAS 错误 | 主节点健康从节点数量不足 | 查看主节点info replication,确认 connected_slaves 数量和 lag | 检查从节点网络、主从复制状态;根据业务容忍度调整 min-replicas 参数 |
主节点日志出现+switch-master,但客户端没有感知 | 客户端没有通过哨兵获取主节点地址 | 查看客户端连接配置,是否使用 Sentinel-aware 模式 | 改用带哨兵感知的客户端 API,订阅主节点切换事件 |
| 网络恢复后旧主数据被清空 | 哨兵将旧主降级为从节点并执行全量同步 | 检查旧主info replication的 run_id 和数据量变化 | 配置 min-replicas-to-write 从源头避免旧主写入 |
| 脑裂期间写请求超时而非报错 | 旧主网络隔离但 TCP 连接未断开,请求迟迟得不到响应 | 抓包确认连接状态;查看应用端超时配置 | 在客户端设置合理的超时时间,配合 Redis 侧 min-replicas 快速拒绝 |
| 哨兵判定主观下线过于频繁 | down-after-milliseconds设置过小,主节点因负载高或 GC 停顿误判 | 查看哨兵日志中 sdown 的触发时间和主节点负载 | 调大 down-after-milliseconds,降低误判概率 |
| 主节点切换后,数据延迟很大 | 从节点的复制积压缓冲区设置过小,导致切换后需要全量同步 | 查看从节点日志中是否有 full resync | 调大 repl-backlog-size,减少全量同步频率 |
8.1 排查思路的顺序
遇到疑似脑裂问题时,建议按下面的顺序排查:
- 先看哨兵日志,确认是否发生过主备切换。
- 再对比主从节点的
run_id,查看历史上是否有多个 run_id 交替。 - 然后检查主从节点的
info replication,确认当前角色和数据同步状态。 - 最后通过
slowlog和应用日志,定位数据丢失的时间窗口,确认是否与主备切换时间吻合。
要注意的是,Redis 本身没有直接记录“脑裂事件”的日志项,需要结合哨兵日志、节点角色变化、客户端错误日志三份信息交叉验证。
9. 最佳实践与工程建议
Redis 脑裂这个问题,越早做防护,成本越低。下面这套配置和方案,是我认为在实际项目里比较稳妥的基线。
9.1 配置层面:至少做到这一步
在所有的 master 节点上,配置:
min-replicas-to-write 1 min-replicas-max-lag 10解释一下为什么是 1 和 10:
min-replicas-to-write 1:只要还有 1 个健康从节点,主节点就继续服务,保证可用性;当从节点全部失联时,拒绝写入,保证一致性。min-replicas-max-lag 10:允许从节点最多延迟 10 秒。10 秒是一个相对合理的阈值,既能容忍网络的瞬时抖动,又不会让数据分歧窗口过大。
如果你的业务对数据一致性要求极高,比如用 Redis 存库存、存订单状态,可以进一步收紧:
min-replicas-to-write 2 min-replicas-max-lag 5但要注意,配置越高,可用性越低。如果只有一个从节点还宕机了,主节点就会拒绝所有写入,这是必须要接受的权衡。
9.2 架构层面:避免单点
- Redis 至少要一主两从,且三个节点分布在不同的物理机器上,最好是不同机架。
- Sentinel 至少部署 3 个实例,
quorum设为 2,保证故障转移需要多数派同意。 - 客户端必须使用哨兵感知的连接方式,不要直连写死的主节点地址。
9.3 客户端层面:记住“收到成功不代表真的安全”
Redis 主从复制是异步的,主节点返回 OK 不代表数据已经同步到从节点。这一点只要使用了主从模式,就无法彻底消除。
所以对于强一致业务,比如分布式锁、扣减库存,还要考虑引入 RedLock 这样的多节点写入方案,或者把最终一致性交给数据库,Redis 只做加速层。
9.4 监控层面:要能第一时间发现切换
建议监控以下指标:
master_link_down_since_seconds:主从连接断开时长。connected_slaves:主节点的从节点数量。master_repl_offset与slave_repl_offset的差:主从复制延迟。- 哨兵日志中
+switch-master的出现频率。
一旦发现主从切换,就要查一下切换原因,确认是真实的节点故障、还是网络抖动误判。不要让脑裂成为“事后才知道”的事。
9.5 上线前做一次故障演练
很多团队直到线上出问题,才第一次见识脑裂。建议在测试环境做一次完整的故障演练:
- 搭建主从 + 哨兵环境。
- 用 iptables 模拟主节点网络分区。
- 观察哨兵是否发生切换。
- 观察旧主节点是否拒绝写入。
- 确认网络恢复后数据是否一致。
整个演练不会超过半天,但能帮团队提前暴露很多配置上的问题。脑裂这种问题,演练时发现,成本很低;线上出现再复盘,可能就是事故报告了。
10. 总结与后续学习方向
Redis 脑裂不是 Redis 特有的缺陷,而是分布式系统在 CAP 约束下必然面对的问题。这篇文章核心讲了四件事:
第一,脑裂的本质是网络分区下,旧主节点还在接收写入,而哨兵已经选出了新主节点,形成两个主节点同时工作的局面。
第二,脑裂导致的数据丢失发生在网络恢复后,旧主被强制降级为从节点并执行全量同步,此前的增量写入被直接覆盖。
第三,最有效的预防手段是配置min-replicas-to-write和min-replicas-max-lag,让旧主在失去健康从节点时拒绝写入,用短暂不可用换取数据不丢失。
第四,生产环境不能只靠 Redis 侧配置,还要在客户端、监控、故障演练三个层面做好配套,才能真正把脑裂的影响降到可控范围。
如果你想把这块继续深入,下面几个方向值得花时间:
- Redis Sentinel 的选主算法和配置细节,理解 quorum 和 majority 的区别。
- Redis Cluster 模式下的网络分区处理机制,它和主从 + 哨兵模式各有取舍。
- 分布式锁场景下 RedLock 的原理和争议,理解它为什么能降低脑裂风险。
- Redis 复制缓冲区(repl-backlog)和全量同步、增量同步的底层机制。
建议先在自己本机把上面那个最小实验跑一遍,亲手看到 NOREPLICAS 错误和数据分叉是什么感觉,再去看源代码和英文文档,会顺畅很多。分布式系统的很多坑,看十遍文档不如亲手踩一次。