zookeeper源码 — 五、处理写请求过程 (2)

follower收到请求之后,先请求请求的opCode类型(这里是create)构造对应的request,然后交给第一个processor执行,follower的第一个processor是FollowerRequestProcessor.

follower转发请求给leader

由于在zk中follower是不能处理写请求的,需要转交给leader处理,在FollowerRequestProcessor中将请求转发给leader,转发请求的调用堆栈是

serialize(OutputArchive, String):82, QuorumPacket (org.apache.zookeeper.server.quorum), QuorumPacket.java writeRecord(Record, String):123, BinaryOutputArchive (org.apache.jute), BinaryOutputArchive.java writePacket(QuorumPacket, boolean):139, Learner (org.apache.zookeeper.server.quorum), Learner.java request(Request):191, Learner (org.apache.zookeeper.server.quorum), Learner.java run():96, FollowerRequestProcessor (org.apache.zookeeper.server.quorum), FollowerRequestProcessor.java

FollowerRequestProcessor是一个线程在zk启动的时候就开始运行,主要逻辑在run方法里面,run方法的主要逻辑是

zookeeper源码 — 五、处理写请求过程

先把请求提交给CommitProcessor(后面leader发送给follower的commit请求对应到这里),然后将请求转发给leader,转发给leader的过程就是构造一个QuorumPacket,通过之前选举通信的端口发送给leader。

leader接收follower请求

leader获取leader地位以后,启动learnhandler,然后一直在LearnerHandler#run循环,接收来自learner的packet,处理流程是:

processRequest(Request):1003, org.apache.zookeeper.server.PrepRequestProcessor.java submitLearnerRequest(Request):150, org.apache.zookeeper.server.quorum.LeaderZooKeeperServer.java run():625, org.apache.zookeeper.server.quorum.LearnerHandler.java

handler判断是REQUEST请求的话交给leader的processor链处理,将请求放入org.apache.zookeeper.server.PrepRequestProcessor#submittedRequests,即leader的第一个processor。这个processor也是一个线程,从submittedRequests中不断拿出请求处理

zookeeper源码 — 五、处理写请求过程

processor主要做了:

交给CommitProcessor等待提交

交给leader的下一个processor处理:ProposalRequestProcessor

leader 发送proposal给follower

ProposalRequestProcessor主要作用就是讲请求交给下一个processor并且发起投票,将proposal发送给所有的follower。

// org.apache.zookeeper.server.quorum.Leader#sendPacket void sendPacket(QuorumPacket qp) { synchronized (forwardingFollowers) { // 所有的follower,observer没有投票权 for (LearnerHandler f : forwardingFollowers) { f.queuePacket(qp); } } } follower 收到proposal

follower处理proposal请求的调用堆栈

processRequest(Request):214, org.apache.zookeeper.server.SyncRequestProcessor.java logRequest(TxnHeader, Record):89, org.apache.zookeeper.server.quorumFollowerZooKeeperServer.java processPacket(QuorumPacket):147, org.apache.zookeeper.server.quorum.Follower.java followLeader():102, org.apache.zookeeper.server.quorum.Follower.java run():1199, org.apache.zookeeper.server.quorum.QuorumPeer.java

将请求放入org.apache.zookeeper.server.SyncRequestProcessor#queuedRequests

follower 发送ack

线程SyncRequestProcessor#run从org.apache.zookeeper.server.SyncRequestProcessor#toFlush中取出请求flush,处理过程

zookeeper源码 — 五、处理写请求过程

follower开始commit,记录txLog和snapShot

发送commit成功请求给leader,也就是follower给leader的ACK

leader收到ack

leader 收到ack后判断是否收到大多数的follower的ack,如果是说明可以commit,commit后同步给follower

zookeeper源码 — 五、处理写请求过程

follower收到commit

还是Follower#followLeader里面的while循环收到leader的commit请求后,调用下面的方法处理

org.apache.zookeeper.server.quorum.FollowerZooKeeperServer#commit

zookeeper源码 — 五、处理写请求过程

最终加入CommitProcessor.committedRequests队列,CommitProcessor主线程发现队列不空表明需要把这个request转发到下一个processor

follower发送请求给客户端

follower的最后一个processor是FinalRequestProcessor,最后会创建对应的节点并且构造response返回给client

总结

本篇文章主要介绍了client发起一次写请求,client、follower和leader各自的处理过程。当然了,为了简单,其中设定了一些具体的场景,比如请求是发送到follower的而不是leader。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydffd.html