YAOTU INSIGHTS

Redis故障04:脑裂问题原理预防与解决

Redis故障04:脑裂问题原理预防与解决
Redis 脑裂原理、预防与解决脑裂不是一个 Redis 特有的概念而是分布式系统里网络分区带来的通用问题。它最危险的结果不是“有两个主节点”这件事本身而是两个主节点各自接受写入网络恢复后其中一个会被降级并清空数据导致已经“成功”的写操作丢失。正常集群网络分区分区 1 选举 Master分区 2 保留旧 Master两个 Master 同时接受写入数据不一致一、什么是脑裂在高可用集群中如果节点之间因为网络故障失去联系就可能各自形成小集群并选举出自己的 leader。此时原本一个集群分裂成多个集群出现多个 master这就是脑裂。脑裂的后果数据不一致不同子集对同一数据做不同写入。重复写入脑裂恢复后某些写操作可能被重复应用。数据丢失旧主被降级后新主向所有 slave 发SLAVEOF命令全量同步前会先清空数据旧主在分区期间的写入会被清掉。二、Redis 的四种部署模式模式优点缺点单机操作简单成本低数据不安全可用性低主从有备份可读写分离不能自动故障转移哨兵自动故障切换存储容量受限需要额外哨兵集群水平扩展高可用性能好运维和编程复杂度增加Redis 部署模式单机主从复制哨兵Cluster无高可用手动切换自动故障转移无分片自动故障转移 数据分片三、哨兵模式下的脑裂哨兵模式下的脑裂通常是 master、slave、sentinel 被网络分割到不同分区。哨兵感知不到旧 master就会把某个 slave 提升为新 master如果旧 master 的客户端连接还没断开就出现新老 master 同时服务。客户端 2客户端 1Sentinel 集群Slave 2Slave 1旧 Master客户端 2客户端 1Sentinel 集群Slave 2Slave 1旧 Master网络分区导致 Sentinel 联系不上旧 Master两个 Master 同时服务判断 Master 客观下线选举并提升为新 Master写入新 Master仍写入旧 Master1. Sentinel 的三大任务哨兵负责监控持续监控 master、slave 是否在线。自动切换主库master 故障时选出新 master。通知让 slave 执行replicaof并通知客户端连接新 master。2. 主观下线和客观下线Sentinel 默认每秒向节点发送PING。如果一个节点没有按时返回有效回复单个 Sentinel 会把它标记为“主观下线”。为了降低网络抖动带来的误判Sentinel 集群会投票。超过quorum数量的 Sentinel 都认为 master 主观下线时才把它标记为“客观下线”触发故障转移。sentinel monitor master-name master-host master-port quorum sentinel monitor mymaster 127.0.0.1 6379 2quorum通常设置为N/2 1也就是过半机制。是否否是Sentinel PING 节点有效回复节点在线单实例标记主观下线 SDOWN达到 quorum 个 Sentinel 同意继续观察不切换标记客观下线 ODOWN启动故障转移3. 哨兵集群自身的脑裂哨兵节点本身也应高可用否则单点哨兵挂掉后Redis 后续故障就没人处理。部署建议Sentinel 节点数量为奇数至少 3 个。法定人数设置为N/2 1。这样可以避免偶数节点时两个大小相等的分组各自选出不同 master。4. 哨兵模式脑裂的预防# sentinel.conf sentinel monitor mymaster ip redis-port quorum重点参数down-after-millisecondsSentinel 多久未收到响应后判定主观下线。failover-timeout故障转移超时时间影响两次 failover 间隔、slave 同步新 master 的最大时间等。sentinel down-after-milliseconds mymaster 30000 sentinel failover-timeout mymaster 180000参数设置需要平衡过短容易误判过长会延迟故障恢复。四、Cluster 模式下的脑裂Redis Cluster 使用 Gossip 协议通信并自动进行故障检测和故障转移。某个主节点与从节点失联时其他节点可能选举出新的主节点而旧主仍然可能接受客户端写入于是出现脑裂。集群客户端Slave原 Master集群客户端Slave原 MasterT1原 Master 与 Slave 失联但仍连接客户端T2集群判定原 Master 失联脑裂两个 MasterT3网络恢复原 Master 回归全量同步前清空自身数据写入数据提升为新 Master降级为新 Master 的 SlaveSLAVEOF 新 Master1. 用min-slaves-to-write限制旧主写入Cluster 模式无法像 Zookeeper 那样用强一致过半机制彻底避免脑裂但可以通过“没有足够健康从节点就拒绝写入”来缩小数据丢失窗口。# 至少要有 1 个从节点且同步延迟不超过 10 秒主节点才接受写请求 min-slaves-to-write 1 min-slaves-max-lag 10参数含义min-slaves-to-write主库能接受写入前至少连接的从库数量。min-slaves-max-lag从库给主库发送 ACK 的最大允许延迟单位秒。例如设置为1和10如果旧主已经和从节点失联 12 秒那么没有从节点满足“延迟小于 10 秒”的条件旧主就会拒绝写入从而避免分区期间产生无法恢复的脏数据。2. 配置实验min-slaves-to-write 1 min-slaves-max-lag 10验证思路搭建 3 主 3 从 Cluster。停掉一个 slave。观察 master 是否仍接受写入。重启 slave 后恢复。注意这个配置会影响可用性。如果 slave 少于min-slaves-to-write即使 leader 正常主节点也会拒绝写入所以需要根据业务对可用性和一致性的容忍度权衡。五、为什么 Redis 脑裂不能彻底解决Redis Cluster 的官方定位是最终一致不能保证强一致Redis 主从复制是异步的。故障检测和切换依赖节点间通信无法做到任何时刻都只有一个可写主节点。min-slaves-to-write和min-slaves-max-lag只能“尽量规避”不能“彻底解决”。因此 Redis 更偏向 AP。对于账户余额、资金流水这类强一致场景应选择传统关系型数据库或 Zookeeper 等 CP 组件而不是让 Redis 去承担强一致职责。业务是否需要强一致是MySQL / Zookeeper / etcd否优先性能和可用性Redis Cluster / Sentinel用 min-replicas 参数限制丢失窗口接受最终一致配合业务补偿小结面对 Redis 脑裂时要区分“哨兵模式脑裂”和“Cluster 模式脑裂”。前者需要从哨兵奇数部署、quorum过半、主观/客观下线与超时参数入手后者主要用min-slaves-to-write和min-slaves-max-lag限制旧主写入但仍无法做到强一致。关键是明白 Redis 的 AP 定位和异步复制是脑裂无法被彻底消灭的根本原因。