1 zk的leader和follower之间的连贯
(1)leader选举胜利后,状态扭转,执行lead办法,lead()办法其实就是启动了个LearnCnxAcceptor线程,为了承受其余follower/observer的申请。用的是传统的bio,
a LearnerCnxAcceptor线程start启动 b LearnerCnxAcceptor线程调用accept,期待其余follower连贯 c 其余follower连贯建设,则生成这个follower专用的LearnerHandler线程,并start d LearnerHandler线程代表了对follower的申请收发,通过while循环阻塞读取follower的申请,申请包含注册,proposal的ack,ping等等。 e 读取申请后,通过jute的反序列化和定制的协定规定,解析申请数据并解决。
(2)follower身份确立后,状态扭转,执行Follwer的followLeader办法,做这几个事:
a findLeader,找到leader是哪个机器 b connectToLeader,对leader发动连贯,此时leader如果连贯建设会生成LearnerHandler c 向leader发动注册,次要是follower信息。 d while循环,阻塞式的读取和解决leader发来的申请,proposal commit等操作。
leader和follower次要通过jute来进行序列化/反序列化,数据用单词开始完结 ,如type xxxxx type,代表type的内容。
2 客户端和服务端的连贯建设
(1)客户端启动,其实就是new Zookeeper实例,构造方法中会初始化一个ClientCnxn组件,用于和server端连贯通信。clientCnx 启动,run办法里while循环,再循环中一直收回ping和数据包
a 如果没连贯,ClientCnxnSocketNIO的registerAndConnect创立连贯, b 连贯建设后,判断上次发动ping的工夫距离,通过sendping和服务端发动心跳 c 基于底层封装的clientCnxnSocket,通过nio的读写事件遍历selectkey对读写事件进行解决。
(2)服务端就是quorumpeer启动的时候启动起来的NIOServerCnxnFactory,应用的通用的nio,通过configure计算应用的线程数,实际上是2*cpu核数的worker线程和一个固定的accept建设连接线程。因为客户端不肯定特地多,所以一个accept也够用。接下来accept的run承受accept事件,而后注册read事件,应用select解决具体读写事件。
3 session治理
(1)session的创立流程:
a zookeeper客户端创立后,会定时ping到server,申请入本人的队列,而后由nio组件生产队列通过下<mark style="color:transparent">来源gaodaimacom搞#代%码网</mark>面说的连贯发到server端, b server端通过启动的NIOServerCnxnFactory网络组件承受申请,拆包转化。 c 如果第一次申请,没有session,会进入processConnectRequest,应用sessionTraker组件创立惟一sessionid。 d 而后把这次session存到sessionid为key的map中,并进行touch分桶,治理seesion申明周期。前面每次申请都会touch一下分到新的过期桶。 e 这次session申请submit到解决链中。 f 解决链一层层走上来,走完写回后果到客户端。创立session的话解决链做的不多,解决链出要给前面proposal和commit二次提交用。
(2)sessionid:通过机器标识(配置的myid)+工夫戳位移,失去惟一id。分桶策略:ExpirationTime是指该会话最近一次可能超时的工夫点,ExpirationTime = CurrentTime + SessionTimeout,sessionTracker的run会定时查看会话,其工夫距离为ExpirationInterval(默认配置的ticktime)。
(3)session的状态轮转
session的次要作用是判断长期节点是否还保留。
a Connected/Reconnected->Suspended 表明心跳超时, Session 可能将会生效(长期节点可能会隐没); b Suspended->Lost 表明曾经连贯上Server和服务器确认了Session超时,或者客服端长期无奈连贯到服务端,此事Session曾经齐全无奈再应用(长期节点隐没了); c Suspended->Reconnected 从新连贯上Server,并且Session可能持续应用(长期节点还存在); d Suspended->Lost->Reconnected 从新连贯上Server,然而Session曾经从新创立(长期节点须要从新创立)
(4)session的touch激活
client收回激活申请的机会:
a 客户端向服务端发送申请,包含读写申请,就会触发会话激活。 b 客户端发现在sessionTimeout/3工夫内尚未与服务端进行任何通信,就会被动发动ping申请,服务端收到该申请后,就会触发会话激活。
(5)session的检测和清理
sessionTracker的run办法定期检测,
a 设置session状态位敞开,革除过期的桶 b 提交一个closeSession的本地申请到解决链,和失常申请一样进行一个2pc的删除,删除内存长期节点。session保留了本人创立的所有长期节点,间接删十分不便。删了当前还会触发watcher。 c 移除会话,把session对象移除sessionTracker.removeSession(sessionId); d 从NIOServerCnxFactory里,依照规范的nio敞开流程敞开session对应的连贯。
4 2pc提交流程剖析
从client客户端的create开始,发送到zkserver的leader机器。leader有本人的proposal解决链,对所有follower发送proposal,同时本人用一个proposal的ack汇合收集返回的ack,过半后触发commit
a 客户端create,申请进入客户端的发送队列outgoingqueue,有clientcnx的sendthread线程发送申请进来,达到zkserver服务器的NIOServerCnxnFactory组件,提交给解决链。如果申请到了follower,follower实现转发。 b 解决链达到ProposalRequestProcessor,开启2.1,进入proposal办法,放入outstandingProposals队列,遍历所有leaner组件(这里learner能够看作follower),发送proposal到每个follower c follower接管到proposal申请后,对数据包进行解决,先提交到Synprocessor线程进行刷内存数据库和刷盘,这里看到数据是写入内存的,刷盘是数据包队列为空或累计了1000条事务数据后再刷盘。而后通过SendAckRequestProcessor返回ack,这些processor名字很容易了解。 d leader收到proposal的ack后,边收集边统计,如果ack过半,则trycommit,本人先commit,而后异步发送commit到所有follower。leader本人commit完就能对外应用了,不必等commit的ack,leader本人commit是通过FinalRequestProcessor,写入内存数据库zkDatabase,反馈给客户端后果。 e follower收到commit,本人更新数据,逻辑和leader的commit一样。
还有些细节:
(1)leader接管写申请的时候,第一个processor,PreRequestProcessor里生成的事务id,zxid怎么生成?其实就是个原子long递增hzxid.incrementAndGet();
(2)全量数据快照的存储:SyncRequestProcessor里,一直读事务申请存内存的时候,会判断是否须要落整体快照(依据配置大小来判断),需要的话就开启写盘线程,通过序列化把内存树写入磁盘。
(3) qurumPeerMain启动的时候,有个DatadirCleanupManager,启动PurgeTask清理文件,因为快照都是全量的,后面的快照能够删,通过这个线程能够清理。
(4)leader和follower的解决链: