由浅入深理解Paxos(2)
作者:宋利兵
来源:MySQL代码研究(mysqlcode)
3 - 原子广播系统(Paxos)的性能优化
在《由浅入深理解Paxos(1)》里,原子广播系统的协议可以很好解决一致性问题,但是它的性能不够好。当系统中节点比较多、并发量很大时,每个存储位置的竞争都会非常激烈,这会导致很多的无效通讯,效率非常不好。
- Leader 分发器
一个很有效的解决办法是指定一个分发器为Leader分发器,当其他分发器收到数据以后,将数据转发给Leader分发器。Leader分发器按照接收的顺序,一个一个的执行原子广播协议过程。
有人可能会问了,既然这样还用执行原子广播的协议吗?当然需要,因为实际环境中总会有故障,很可能导致多个节点都认为自己是Leader。如果Leader在正常执行的过程中不执行原子广播协议,出现故障后就没办法保证数据的一致性。
- Leader 的选取
在选取Leader时,没有太多的限制。任何分发器都可以作为Leader,只要所有的分发器按照同样的规则选取Leader就可以了。比如:
按照分发器ID的顺序,由大到小(或者由小到大)的顺序来选取。
按照IP地址和端口号的的顺序来选取。
甚至根据用户指定的顺序选取Leader(用户可以依据机器的性能,新旧程度来指定顺序)。
原子广播协议可以保证:多个Leader同时工作不会导致数据的不一致。所以原子广播协议对Leader的选举过程没有什么限制,一个简单的过程如下(实现的时候可以按自己的想法去定义):
当没有Leader或者Leader超过一定时间没有响应时,一个节点可以发起一个Leader选举请求。选取请求中包含当前分发器的ID。
收到Leader请求的节点,如果认为自己应该做Leader(自己的ID比Leader请求者的ID大),则再发起一个Leader请求。
任何节点在收到Leader请求后,等待一段时间。如果没有收到其他的Leader请求,则从所有收到的Leader请求中选取Leader(选取ID最大的分发器作为Leader)。
- 减少网络通讯次数
一个完整的原子广播协议过程需要5次网络通讯,如下图所示:
由于每个存储位置都是由Leader来发起原子广播协议过程的,我们可以让Leader预先对多个存储位置加锁。对多个存储位置加锁的请求可以放在同一个数据包中,返回结果也同样放在同一个数据包中。如下图所示:
当有数据请求时,直接从第三步开始执行就可以了。
- 总结
引入Leader机制后,这个原子广播系统已经是一个实际可用了系统了。尽管很多细节没有涉及到,但是原子广播系统的核心架构已经比较清楚了。首先我们把系统看做是一个状态机,通过状态机的原理我们将分布式系统中的一致性问题转换成了全局排序的问题。这不但简化了分布式系统的实现,而且使得分布式的机制变成了一个通用的机制。
原子广播系统主要有两大部分,分别解决两个不同的问题。
原子广播协议 - 用来解决多个副本之间的一致性问题。
Leader - 用来解决协议的效率问题
4 - Paxos协议解析
在理解Paxos协议时,首先要弄清楚Paxos在解决什么问题。Paxos就是在解决全局排序的问题。我们可以将Paxos协议中的牧师(Priest)对应为原子广播系统中的分发器,牧师的账本则是存储队列。如下图所示:
Paxos中术语和原子广播系统的对应关系
Priest - 分发器
Ledger - 存储队列
Decree - 用户数据
Decree Number - 存储位置序号
Ballot - 分发器执行的一个原子广播协议(的6个步骤)过程
Ballot Number - 锁的优先级
The Single-Decree Synod
Synod 可以理解为一段时间内原子广播系统的状态,在这段时间内没有分发器(牧师)的加入或者退出。Single-Decree Synod则指的是原子广播系统的存储队列只有一个存储位置。因此在Single-Decree Synod中就不需要考虑该往哪个存储位置存储的问题。
Single-Decree Synod 中描述了两个协议
The Basic Protocol
The Complete Protocol
Basic Protocol 描述的是原子广播协议在一个存储位置上存储数据的过程。而 Complete Protocol则引入了Leader的概念。
The Multi-Decree Parliament
The Multi-Decree Parliament则等同于我们的原子广播系统,它有多个存储位置。因此在The Multi-Decree Parliament中需要用到Decree Number去区分存储位置。The Multi-Decree Parliament中讲解了对The Complete Protocol的优化,即一次通讯中对多个存储位置加锁的方法。
以上部分是对Lamport老爷子的《The Part-Time Parliament》的解析。
- 分发器(牧师)内部模块划分
在Lamport另外的一个文章《Paxos Made Simple》中将牧师分成了三个角色:
Proposer - 负责发起原子广播协议
Acceptor - 负责加锁和预写入
Learner - 负责写入存储队列
分发器的内部构造如下图所示:
这样划分以后,每个角色的职责都很清晰,理解起来也比较容易。另外在多数派协议中的多数是包括自己的,从这个图上看就很好理解了,因为Proposer所在的分发器上也有Acceptor的角色。
推荐订阅原文作者 宋利兵 的公众号 MySQL代码研究