网上很多文章都是将Raft和Paxos对比,但个人觉得Raft和MySQL高可用方案更为相近。所以在此做个比较加深理解。 如有错误,还请指正,谢谢。
简介
数据库容灾的基础是副本。副本间同步的关键是日志,所以只要日志已持久化到备用副本,数据就不会丢。
MySQL的主从复制
MySQL在半同步出现前,主从复制模式都是异步复制。
1. Binlog
的产生是顺序的。
2. RelayLog
是顺序写。
3. RelayLog
应用的过程,已经优化成了并行回放。
4. ROW
格式的Binlog
是幂等的。
5. GTID
使得日志有全局唯一ID。
如果只有异步同步,是做不到强一致性的。好在MySQL发展出了半同步。
MySQL半同步(Semi-sync)简介
特点
- 主库在存储层正式Commit事务之前,会等待从库的
ACK
- 从库会在
Binlog
写入RelayLog
后,返回ACK
。 - 如果主库等待从库响应,半同步会退化成异步。
分析
从半同步的设计可以看出,MySQL的主从复制更倾向于可用性,而不是主备成强一致。半同步牺牲了少许的延时,换来了更高的数据可靠性。
在日志同步顺利的情况下,半同步具备强一致。同步异常的情况下退化成异步复制,一致性降为弱一致。这应该也是被称为半同步的原因。 如果在同步异常的情况下,Master死等Slave响应,不自动退化成异步复制。则是强同步的逻辑,只是此时Master的写入也会被阻塞,PostgreSQL支持强同步。
MySQL的高可用方案
如果我们也是用多副本,加上辅助系统,是否也能做到接近Raft的可用性呢? 1. 三节点,一主二备。 2. 启用半同步。 3. 高可用模块,比如MHA,自身用Zookeeper保证可用性。
对比分析
三副本
对于MySQL半同步而言,3个节点中只要有一个节点返回ACK,事务即可提交,基本等同于n/2 1
形成多数派。
注意: 半同步收到一个ACK
就Commit
了,对于5节点甚至更多节点,就不适合了。不过这应该也就是个参数问题。
日志不可撤销
无论是MySQL还是Raft,在主节点不变的情况下,日志持久化后,是不能撤销的。主节点会不惜余力的把日志推送到其它节点。
连续的日志
日志传输和异步复制一样,IO线程都是单线程。日志的传输是一个单通道,所以如果中间出现异常,备库也会卡在这个位点,直到恢复。 这种情况MySQL半同步和Raft一样,二者都必须等前一条日志复制成功,才能复制下一条日志。
所以,在MySQL不退化成异步复制的情况下,二者可用性相同。
选主
Raft具备自动选主的能力,MySQL不具备。MySQL需要外部的高可用模块来选择新主。 相同点在于,二者都会选择日志最多的节点作为新主。这在只有2个节点时是没得选的。
在依托HA的情况下,MySQL也可以选出正确的新主库。然后将活动的备库指向新主库。
回滚回补
这是MySQL高可用的一个能力,用于解决在老主库宕机后,新主库已经提供服务的情况下,原主库恢复时的处理。 由于老主库宕机时,可能会有已经持久化,但未同步给新库的事务。 此时,HA会提取老主库的日志,并回滚掉老主库未推送到备库的日志。然后酌情应用到新主库中(用于兼容异步复制的情况)。
这个地方,Raft也会类似的截断老节点的未提交事务,但的规则更为复杂。参考资料
总结
Raft像是一个具备自选主能力的MySQL半同步机制加强版。在机制上要比MySQL更复杂,除了自选主外,也有更多的限制条件。 但看上去MySQL的高可用机制,比Paxos算法更贴近Raft协议。