1、Zookeeper内部原理
留意zookeeper的特点
(1)注意zookeeper所有集群都是1主N从的形式。
(2)Zookeeper配置的时候并没有主从(hdfs配置的时候是有指定主从的),但是运行的时候就是有分leader和follower,这东西怎么出来的?选举。
(3)其实这个全局一致不太好保持。如果读写频率高,如何确定这个东西是一致的?
(4) 更新请求。这个更神奇。即使先收到2再收到1,也会先写1再写2。
(5)数据更新原子性。要么全成功,要么全失败。不会出现2台成功3台失败的情况。
这一切都尽在内部原理中介绍。
2、节点类型
是否带-s参数:有序与无序;是否带-e参数:临时与永久。所以节点类型总共有4种。
这个前面已经有所介绍了。
3、Stat结构体
1)czxid-创建节点的事务zxid
每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。
事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。
比如执行了一系列的操作,每一个操作都有一个序号,这个序号就是这串东西,是一个64bit的数。这里的zxid共9个字节。
后面8个字节代表当前服务器启动操作的次数,前一个字节表示该服务器启动到第几次了。所以合起来就表示:第2次启动服务器的第3次操作创建的节点。
2)ctime - znode被创建的毫秒数(从1970年开始)
3)mzxid - znode最后更新的事务zxid
这里就表示,第2次启动服务器的第11次操作是最后一次修改了该节点。
4)mtime - znode最后修改的毫秒数(从1970年开始)
5)pZxid-znode最后更新的子节点zxid
这里就表示,第2次启动服务器的第3次操作是最后一次更新了它的子节点。
6)cversion - znode子节点变化号,znode子节点修改次数
7)dataversion - znode数据变化号
8)aclVersion - znode访问控制列表的变化号。ACL就是访问控制列表(Access Control List)。就是访问一个节点的权限。
Zookeeper支持给每个节点设置只有特定服务器能访问它。这个其实就是网络安全。一般默认是谁都可以访问的ACL。(就是Linux文件权限的777)
9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
10)dataLength- znode的数据长度
11)numChildren - znode子节点数量
这个前面已经有所介绍了。
4、监听器原理(面试重点)
Zookeeper有个重要的功能叫通知。通知的原理大致是:
Zookeeper对于每个节点都存在watcher list。 所有人,如果要观察这个节点,就告诉zookeeper要watch它,这样zookeeper就把你放进watcher list。假设出现了变化,就遍历这个watcher list,逐个通知,通知完了,就把你从watcher list中删除。
留意ZooKeeper构造方法中
这里有个ClientCoxn。这里就是生成两个子线程的地方。Zookeeper的Client和Server通信是异步的,异步通信一定有子线程,子线程就是在这里生成的。
这两个就是线程类SendThread和EventThread。它们都继承ZooKeeperThread。
所谓的ZooKeeperThread继承了Thread。
然后接下来是start(),就是在new ZooKeeper的时候,ZooKeeper就已经生成了两个子线程。一个是sendThread、一个是eventThread。
我们所有的注册请求都是通过sendThread异步发给服务端的;eventThread就是等着服务端通知我们什么事,然后调用回调函数process。
举个例子,一个集群的董事长,平时时间很宝贵,工作不能停。现在要跟另一个老总沟通,但不能等着他。此时可以告诉第一个秘书(负责发):今天有什么事找张老板,你把这个事发给他;再告诉第二个秘书(负责收):如果张老板有会话,你以什么方式通知我。这里的第二个过程就叫回调函数。
Zookeeper是怎样保证高并发情况下,全局数据一定,且读写顺序一致?主要是通过ZAB(Zookeeper Atomic Broadcast)协议。这个也是Zookeeper原理中最重要的一部分内容,理解这个就能理解Zookeeper。
ZAB协议主要内容是两个部分。一是没有leader选leader。二是有leader就干活。
Zookeeper刚建立集群的时候没有leader,因此进入第一个阶段。选择一个leader。选出来后,进入第二阶段,干活。以后Zookeeper就在这两个状态之间不停的切换。
follower挂了没事。假设leader挂了,就重新回到第一阶段,选择leader。然后再回到第二阶段。Zookeeper就是在这两个状态之间不停切换。
5、Paxos算法(扩展)
Paxos算法一种基于消息传递且具有高度容错特性的一致性算法。(Zookeeper的ZAB协议设计的时候,参考了很多Paxos思想的细节。该章节作为扩展,了解即可。)
分布式系统中的节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。基于消息传递通信模型的分布式系统,不可避免的会发生以下错误:进程可能会慢、被杀死或者重启,消息可能会延迟、丢失、重复,在基础 Paxos 场景中,先不考虑可能出现消息篡改即拜占庭错误的情况。Paxos 算法解决的问题是在一个可能发生上述异常的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。
Paxos算法流程中的每条消息描述如下:
1.Prepare: Proposer生成全局唯一且递增的Proposal ID (可使用时间戳加Server ID),向所有Acceptors发送Prepare请求,这里无需携带提案内容,只携带Proposal ID即可。
2.Promise: Acceptors收到Prepare请求后,做出“两个承诺,一个应答”。
两个承诺:
a.不再接受Proposal ID小于等于(注意:这里是<= )当前请求的Prepare请求。
b.不再接受Proposal ID小于(注意:这里是< )当前请求的Propose请求。
一个应答:
c.不违背以前做出的承诺下,回复已经Accept过的提案中Proposal ID最大的那个提案的Value和Proposal ID,没有则返回空值。
3.Propose: Proposer 收到多数Acceptors的Promise应答后,从应答中选择Proposal ID最大的提案的Value,作为本次要发起的提案。如果所有应答的提案Value均为空值,则可以自己随意决定提案Value。然后携带当前Proposal ID,向所有Acceptors发送Propose请求。
4.Accept: Acceptor收到Propose请求后,在不违背自己之前做出的承诺下,接受并持久化当前Proposal ID和提案Value。
5.Learn: Proposer收到多数Acceptors的Accept后,决议形成,将形成的决议发送给所有Learners。
下面我们针对上述描述做三种情况的推演举例:为了简化流程,我们这里不设置Learner。
造成这种情况的原因是系统中有一个以上的Proposer,多个Proposers相互争夺Acceptors,造成迟迟无法达成一致的情况。针对这种情况,一种改进的Paxos算法被提出:从系统中选出一个节点作为Leader,只有Leader能够发起提案。这样,一次Paxos流程中只有一个Proposer,不会出现活锁的情况,此时只会出现例子中第一种情况。