(1)投票的时候的源码架构图
刚进入程序,解析完配置文件后,会调用QromaPeer的start方法,做了以下四步
1.加载数据(datatree快照和事务日志文件,当然只加载datatree快照)
2.开启读取数据的线程(recvworker):开启channel.accept来接收其他服务器的请求,开始监听。
3.进行领导者选举,确定服务器的角色,再针对不同的服务器进行初始化操作,比如ServerSocket.accept来等待接收vote,以及应用层的sendqueue和recvqueue之类的,以及传输层的三个map,服务器对应的阻塞队列,线程,以及最近发送的vote。
4.本地的start方法开始,整个选举逻辑,如下:
while(程序运行)
1.直接判断当前state,如果是looking,那么就如下红色字,
2.如果是leader,另外一套逻辑
3.如果是foller。。
4.如果是observer
可以知道zookeeper选举机制的代码实现步骤
1.首先有个Map<Long,Vote>的投票箱
2.然后先投给自己,发送到sendqueue-->(每个其他id都一个专属的队列和对应的线程,没错就是异步处理机制(通过Map<Long,ArrayBlockingQueue>得到,原因是每个队列都需要存储vote,有些机器启动了,也要消费掉以前的) ,然后建立socket发送)
3.第一个循环开始,如果自己的state还是Looking的时候
4.从recvqueue中取得对应的投票通知n
5.如果n是null,可能已经发送过一次了,如果连接还没建立,那么重新发送一次,或者尝试连接所有的投票的服务器(延时建立socker发送vote)(还有个小细节,如果自己的myid比发送的机器大,就建立连接发送,不然关闭,)
6.如果收到了,就看n的状态,如果n也是looking,那么大家来比较,从epoch->zxid->myid进行比较,然后放入投票箱,是否过半统计,直到选到leader,状态改变
PS,详解下 epoch->zxid->myid进行比较过程,epoch就是判断是第几届的投票,如果小于本程序投票的届,直接无视。如果是本届,与当前投票的候选人比较看谁获选,如果大于本程序投票的届,清空投票箱,将自己与其比较。。。。。 最后记得放入投票箱,然后过半统计.
另外:
1.直到有sendWork和recvWork两种线程,如果自己已经是foller或者leader了,recvWork在接收到一张来自于looking状态的选票的时候,会直接返回发送一张投leader的选票(扔到sendqueue)。
(2)主从同步
1.master节点收到客户写请求
2.master预写入且将预写入指令发给其他slaves节点
3.其他slaves节点收到且半数以上发送ack
4.master此时发送指令给其他slaves节点,要求commit,然后自己commit,流程结束。
==》从上面可以看到是弱一致性,但是通过强制让slave发送SYNC给master节点来实现强一致性。能强制补上所有的TXID的数据。