首先说明
- 脑裂的情况出现在主从+哨兵的模式下!
整体流程
- 主节点因为网络原因和从节点断开了连接,但依旧堆外提供服务的能力。(即:还是可以写入数据) 一段时间后,哨兵发现主节点失联了,然后就会到从节点中选举一个作为主节点对外提供服务。(此时,就有两个主节点对外提供服务了) 一段时间后,原先的主节点网络恢复正常,因为已经重新选举了主节点了,因此它(原先的主节点)就会退回成从节点,并向新的主节点请求同步数据;执行的是完全同步,所以会清空掉自己的数据。
因此,最终就会导致:数据的不一致。
导致数据不一致的原因
- 主节点因为网络原因和从节点断连后,依旧可以对外提供服务。(主要原因)
- 原先的主节点恢复网络后,会清空自身的数据。
减少脑裂的数据丢的方案
- 主节点必须要有至少N个从节点连接,如果小于这个数,主节点会禁止写数据。。参数:min-slaves-to-write x,
- 主从数据复制和同步的延迟不能超过 x 秒,如果主从同步的延迟超过 x 秒,主节点会禁止写数据。参数:min-slaves-max-lag x。(起到双重保证作用)
这两个配置项组合后的要求是,主节点连接的从节点中至少有 N 个从节点,「并且」主节点进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主节点就不会再接收客户端的写请求了。
即使原主节点是假故障,它在假故障期间也无法响应哨兵心跳,也不能和从节点进行同步,自然也就无法和从节点进行 ACK 确认了。这样一来,min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主节点就会被限制接收客户端写请求,客户端也就不能在原主节点中写入新数据了。
等到新主节点上线时,就只有新主节点能接收和处理客户端请求,此时,新写的数据会被直接写到新主节点中。而原主节点会被哨兵降为从节点,即使它的数据被清空了,也不会有新数据丢失。