用普通MySQL高可用的方式打开Raft

  • A+
所属分类:分布式系统

网上很多文章都是将Raft和Paxos对比,但个人觉得Raft和MySQL高可用方案更为相近。所以在此做个比较加深理解。
如有错误,欢迎讨论。

简介

数据库容灾的基础是副本。副本间同步的关键是日志,所以只要日志已持久化到备用副本,数据就不会丢。

MySQL的主从复制

MySQL在半同步出现前,主从复制模式都是异步复制。
1. Binlog的产生是顺序的。
2. RelayLog是顺序写。
3. RelayLog应用的过程,已经优化成了并行回放。
4. ROW格式的Binlog是幂等的。
5. GTID使得日志有全局唯一ID。

如果只有异步同步,是做不到强一致性的。好在MySQL发展出了半同步。

MySQL半同步(Semi-sync)简介

用普通MySQL高可用的方式打开Raft

特点

  1. 主库在存储层正式Commit事务之前,会等待从库的ACK
  2. 从库会在Binlog写入RelayLog后,返回ACK
  3. 如果主库等待从库响应,半同步会退化成异步。

分析

从半同步的设计可以看出,MySQL的主从复制更倾向于可用性,而不是主备成强一致。半同步牺牲了少许的延时,换来了更高的数据可靠性

在日志同步顺利的情况下,半同步具备强一致。同步异常的情况下退化成异步复制,一致性降为弱一致。这应该也是被称为半同步的原因。
如果在同步异常的情况下,Master死等Slave响应,不自动退化成异步复制。则是强同步的逻辑,只是此时Master的写入也会被阻塞,PostgreSQL支持强同步。

MySQL的高可用方案

如果我们也是用多副本,加上辅助系统,是否也能做到接近Raft的可用性呢
1. 三节点,一主二备。
2. 启用半同步。
3. 高可用模块,比如MHA,自身用Zookeeper保证可用性。

对比分析

三副本

对于MySQL半同步而言,3个节点中只要有一个节点返回ACK,事务即可提交,基本等同于n/2+1形成多数派

注意: 半同步收到一个ACKCommit了,对于5节点甚至更多节点,就不适合了。不过这应该也就是个参数问题。

日志不可撤销

无论是MySQL还是Raft,在主节点不变的情况下,日志持久化后,是不能撤销的。主节点会不惜余力的把日志推送到其它节点。

连续的日志

日志传输和异步复制一样,IO线程都是单线程。日志的传输是一个单通道,所以如果中间出现异常,备库也会卡在这个位点,直到恢复
这种情况MySQL半同步和Raft一样,二者都必须等前一条日志复制成功,才能复制下一条日志

所以,在MySQL不退化成异步复制的情况下,二者可用性相同

选主

Raft具备自动选主的能力,MySQL不具备。MySQL需要外部的高可用模块来选择新主。
相同点在于,二者都会选择日志最多的节点作为新主。这在只有2个节点时是没得选的。

在依托HA的情况下,MySQL也可以选出正确的新主库。然后将活动的备库指向新主库。

回滚回补

这是MySQL高可用的一个能力,用于解决在老主库宕机后,新主库已经提供服务的情况下,原主库恢复时的处理。
由于老主库宕机时,可能会有已经持久化,但未同步给新库的事务。
此时,HA会提取老主库的日志,并回滚掉老主库未推送到备库的日志。然后酌情应用到新主库中(用于兼容异步复制的情况)。

这个地方,Raft也会类似的截断老节点的未提交事务,但的规则更为复杂。参考资料

总结

Raft像是一个具备自选主能力的MySQL半同步机制加强版。在机制上要比MySQL更复杂,除了自选主外,也有更多的限制条件。
但看上去MySQL的高可用机制,比Paxos算法更贴近Raft协议。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: