zookeeper的核心是一个用来保证所有服务器同步的原子的消息系统。zookeeper所有来自客户端的写请求都会转发到一个单台的服务器上,也就是我们常说的leader。写请求完成之后,会通过原子的消息系统给所有的follower广播本次操作。
保证,属性,和定义
被zookeeper使用的消息系统提供了如下保证:
可靠的传递
给定的消息m,如果被一台服务器传递,m最终会被所有的服务传递。
1、全序
如果一台服务器先传递消息a,然后再传递消息b,那么所有服务器的传递顺序都是a先于b。如果a和b都是被传递的消息,那么不是a在b前面就是b在a前面。
2、因果序
如果消息b在消息a之后发送,同时a消息是被b的发送者发送,那么消息a一定会先于消息b被订购。如果一个发送者在发送b之后再发送c,那么c一定会在b之后订购。
zookeeper的消息系统同样要求是高效的,可靠的,并且易于实现和维护。我们大量地使用了消息,所以需要系统每秒能够处理成千上万的请求。尽管我们可以要求至少k+1个合适的服务器发送新的消息,我们必须能够从像断电之类相关的事故中恢复。当我们实现这个系统的时候,我们有很少的时间和工程资源,所以我们需要有一个工程师可以访问而且易于实现的的协议。
协议假设我们已经在服务器之间建立了点对点的,先进先出的通道。尽管相似的服务通常会假设消息传递可能会丢失或者再次订购,鉴于我们是用tcp进行通信,我们对先进先出通道的假设是非常实际的。确切的说,我们会依赖tcp如下的一些属性:
1、顺序的传递
数据的传输和数据的发送的顺序是一致的而且对于消息m,只有在m之前的发送的所有消息都传递之后,消息m才会被传递。可以推断出,如 果消息m丢失,那么在m之后的所有消息都会丢失。
2、关闭之后没有消息
先进先出的通道关闭之后,从这个通道不会获取到任何消息。
FLP(故障定位台)已经证明在异步的分布式系统中,如果可能发生错误,最终将不会获得一致性。为了确保在错误出现的时候可以获取到一致性,我们使用超时机制。然而,我们依赖时间解决存活问题而不是正确性,所以,如果超机制时停止工作(比如时钟故障),消息系统可能会宕机,但不会违反一致性保证。
当我们描述zookeeper的消息协议的时候,我们用到包,提议,和消息这三个概念。
1、数据包
通过先进先出的通道发送的字节序列
2、提议
协议单元,提议是通过和zookeeper的服务器交换数据包达成的。大多数提议都包含消息,但是NEW_LEADER提议是一个个例,它并不包含消息。
3、消息
会被原子广播到所有zookeeper服务器的字节序列。消息会被译成提议,在发送之前会达成一致。
就像上面所描述的一样,zookeeper保证消息的全序,同时也保证提议的全序。zookeeper使用zxid(zookeeper事务id)去实现全序。所有的提议都会打上zxid标签这,当被提议的时候就会实际的反映出全序。提议被发送到zookeeper服务器,当这些服务告知已收到后,提议会被承认。如果提议包含消息,当提议被承认之后就会发送消息。告知已收到意味着服务会把提议持久化的存储。我们的quorums有这样的要求,任何一对quorum必须至少有一台相同的服务。我们通过要求所有的quorums至少有n/2 +1 个来确保这一点,这里n是指组成zookeeper服务的数目。
zxid有两部分:epoch(时代,纪元)和一个计数器。在我们的实现中,zxid是一个64位的数字,用高32位表示epoch,用低32位表示计数器。因为有两部分表示zxid,zxid既可以用当作一个数字,也可以当做一对整数。epoch表示领导力的改变。每一次新的领导来的时候都会有它自己的epoch。我们有一个简单的算法给提议分配一个唯一的zxid:leader简单的增加xzid,就可以给每一个提议获取到唯一的zxid。领导力的激保证只有一个领导可以使用给定的epoch,所以这个简单的算法可以保证每一个提议都有一个唯一的ID。
zookeeper的消息发送由两个阶段组成
1、领导激活
在这个阶段领导简历正确的系统状态,并准备发起提议。
2、活动消息传递
在这个阶段领导接收要去提议的消息并且协调消息的传递。
zookeeper是一个完整的协议。我们不需要关注个别的提议,只要把协议流看成一个整体就可以了。我们严格的顺序允许我们有效的这样做,并且极大的简化我们的协议。领导激活包含了全部的概念。只有当flfollowers和leader同步之后,并且有相同的状态时,leader才会被激活。这些状态是由所有的提议和跟随leader的的提议组成的,这些所有的提议是指leader认为已经被承认的提议。
领导激活
领导激活包括领导选举。现在在zookeeper中有两个领导选举的算法:LeaderElection 和LeaderElection。zookeeper消息不关心选举一个leader的具体方法,只要满足下面的条件即可:
1、 leader看到了所有的followers的最高的zxid。
2、 所有的quorum都承认追随领导。
这两个要求中的第一个,在followers中的的最高的zxid需要保证正确的操作。第二个要求