`
邢邢色色
  • 浏览: 225590 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

ZooKeeper学习之server端实现的基本骨架

阅读更多

在ZK的源码中,leader,follower和observers的代码结构是高度统一的。在实现中主要的抽象就是request processor了。在处理消息的流水线(pipeline)中有很多不同的阶段,一个request processor代表其中的一个阶段,每一种server类型(无论leader,follower还是observer)实现了某一个特定的request processor的序列(相当于设计模式中的责任链模式,挺常见的)。每一个processor可以任意加到一条处理消息的责任链中。在所有的processor都处理OK之后,一个特定的消息才可以说被完全的处理了。

 

在代码中对应的是RequestProcessor接口,在这个接口中主要的方法是processRequest,它有一个Request的形参。在流水线的各个processor之间使用队列的形式来解耦。当一个processor有一个request要传给下一个processor时,就把request塞到队列中,在下一个processor准备处理这个request前,这个processor保持wait的状态。

 

Standalone模式

最简单的模式就是standalone模式了(参考ZooKeeperServer类,没有实现replication)。下图展示了对应的流水线。它有3个request processor:PrepRequestProcessor,SyncRequestProcessor和FinalRequestProcessor。


 

PrepRequestProcessor接收client的请求并执行,产生一个事务作为处理结果。执行一个操作后产生一个事务的处理结果,结果会直接反馈到ZK的data tree上。事务数据被附加到Request对象上。注意只有会改变ZK状态的操作才会产生一个事务,读操作不会产生事务,Request对象也不会附加事务数据。

 

下一个request processor是SyncRequestProcessor。它负责持久化事务到磁盘上。本质上是把事务按照顺序append到事务日志上,并每隔一段时间产生快照。后面的文章会更详细讨论事务日志和快照。

 

最后的processor是FinalRequestProcessor。当Request对象包括一个事务时它会改变data tree。另一方面,还会读data tree,返回结果给client。

 

Leader模式

当切换到quorum模式时,server的流水线有所改变。来看看leader的流水线吧(LeaderZooKeeperServer),如下图:

 

第一个processor仍然是PrepRequestProcessor,但接下来的processor变成了ProposalRequestProcessor。它负责准备proposal并发送到follower。ProposalRequestProcessor把所有的请求转发到CommitRequestProcessor,另外还把写请求转发给SyncRequestProcessor。

 

SyncRequestProcessor的工作方式与standalone模式一样,持久化事务到磁盘。最后触发AckRequestProcessor,这是一个简单的request processor,它会产生一个ack给自己。leader等待quorum中的每个server的ack,包括它自己,AckRequestProcessor会搞定。

 

ProposalRequestProcessor后面还有其他processor,这就是CommitRequestProcessor。如果接收到足够的ack,它会commit这个proposal。详见Leader类(Leader.processAck()方法)。

 

最后的processor是FinalRequestProcessor,它的作用跟standalone模式下是相同的。它会处理更新请求和读请求(可以将leader配置成不进行持久化,专注于处理proposal,降低负载)。在FinalRequestProcessor之前,还有一个简单的request processor,它负责从要被执行的proposal列表中丢弃不需要处理的proposal,它就是ToBeAppliedRequestProcessor。这个列表就是收到足够的ack的,等待执行的proposal。leader使用这个列表来跟follow进行同步,当收到ack时,会把proposal加到这个列表中。ToBeAppliedRequestProcessor在FinalRequestProcess处理之前丢弃列表中的一些元素。

注意只有更新的请求会被加入这个列表,ToBeAppliedRequestProcessor不会处理读请求。

 

follower和observer模式

接下来讨论follow模式(参考FollowerRequestProcessor类)。下图展示了每一个request processor。注意processor的序列不是唯一的,并且输入的形式有很多种请求,比如client请求,proposal和commit。我们使用箭头来标明follower的不同的路线。



 

首先FollowRequestProcessor接收并处理client的请求,并把请求转发到CommitRequestProcessor,此外还转发写请求到leader,还把读请求直接转发到FinalRequestProcessor。写请求则不一样,CommitRequestProcessor在写请求在FinalRequestProcessor上commit之前保持等待状态。

 

当leader接收到一个新的写请求时,无论是直接的(发生在本机)还是通过learner的,它会产生一个proposal并转发到它的follower。follower一旦接收到一个proposal,就会发送到自己的SyncRequestProcessor。SyncRequestProcessor会处理这个请求,写到事务日志,并转发到SendAckRequestProcessor,它会为这个proposal发送一个ack给leader。leader接收到足够的ack之后会commit这个proposal,leader就会发送commit消息给它的follower(也会发送INFORM消息给对应的observer)。一旦接收到commit消息,follower会用CommitRequestProcessor进行处理。

 

为了保证顺序的执行,CommitRequestProcessor会在接收到写请求时挂起,暂停处理其他请求。这意味着在写请求之后,接收到的任意的读请求会被阻塞,直到写请求完毕为止。通过等待来保证按照接收到的顺序来执行请求。

 

最后,observer的流水线(参考ObserverZooKeeperServer)非常类似follower。但是因为observer不需要对proposal进行ack,所以它没有必要向leader发回ack消息,也没有必要持久化事务到磁盘。如果让observer持久化的话可以加速recovery的过程,关于这点正在进行讨论,以后的release也许会有这项特性。

  • 大小: 24.2 KB
  • 大小: 63.4 KB
  • 大小: 46.2 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics