主从复制

主从之间可以是异步复制,也可以是同步复制。例如 MySQL,在默认情况下采用异步复制,异步复制容易引起数据丢失,比如主从结构中,主节点的写入请求还没有复制到从节点就挂了,当从节点被选为新的主节点之后,在这之前写入没有同步的数据就会被丢失。即便采用了同步复制,也只能提供相对较弱的基本保障,考虑如下情形:主接收写入请求然后发到从节点,从节点写入成功后并发送确认给主,如果此时主节点正准备发送确认信息给客户端时挂了,那么客户端就会认为提交失败,可是从节点已经提交成功了,如果这是从节点被提升为主,那么就出现问题了。

在主从复制结构里,异步复制相比同步复制具备更高的吞吐量和更低延迟,因此,结合同步和异步复制是一个常见选项。比如 Kafka,根据它的声称,这是一个 CA 系统,也就是同时达到数据一致和高可用。Kafka 的复制设计同时包含异步复制和同步复制,同步复制节点组成的集合称为 ISR(In-Sync Replicas),只有 ISR 内的所有节点都对写入确认之后,才算做写成功。当一个节点失效,Leader 会通过 ZooKeeper 感知并把它从 ISR 中移除。不过 Kafka 有一个问题,因为它声称 F 个节点可以容忍 F-1 个节点失效,这跟其他系统不同,通常类似的设计只能容忍 F/2-1 个节点失效,也就是说要确保大多数节点都能正常运行,而 Kafka 这把这个条件弱化成为只有 Leader 运行也可以。这样做是有问题的:假设 ISR 只剩下一个 Leader 在运行,如果此时 Leader 跟 ZooKeeper 的网络连接中断,就会产生一次选举,让 ISR 之外的节点(那些异步复制节点)加入 ISR,通常它会落后此前的 Leader 不少。当原先的 Leader 跟 ZooKeeper 网络连接恢复后,系统就产生脑裂,需要对 2 个 Leader 的数据做 Merge 或者舍弃,后者则会导致数据丢失。