源码项目zookeeper-3.6.3:基础
重点1:Leader,Follower,Observer内部都有一个专门对用户提供服务的服务端,有NIO和Netty两种实现,默认是NIO
重点2:Leader,Follower内部都有一个BIO的客户端和服务端,专门用来举行选举,合法链接是myid小的服务器相对myid大的服务器是客户端
重点3:Leader内部有一个专门用来做同步的BIO服务端,Follower和Observer的内部有一个BIO的客户端
重点4:Observer内部有选举的客户端和服务端,但是发送的选票不被处理,同时接收到选票也不做处理
重点5:如果这个Server的myid比另一个Server的myid小,则先关闭连接,然后对方发起请求跟这个建立连接,这个连接就是合法的;myid大的作为客户端,myid小的作为服务端
三种网络通信
在ZooKeeper内部有三套网络通信机制:选举,同步,CS通信
- 选举过程中的网络通信:BIO 通信实现
- 服务端:相对来说 ID 大的是客户端
- 客户端:相对来说 ID 小的就是服务端
- ID 大的 Server 发起链接请求给 ID 小的 Server,真实情况是,每个节点都会启动服务端
- Follower 和 Leader 之间的状态同步网络通信:BIO 通信实现
- 当选举结束的时候,必然有一个节点是 Leader,其他节点 Follower
- Leader 是 Server,其实 服务端每次接收到一个 Follower 的链接请求,建立连接之后,就会创建一个 LearnerHandler 线程来专门给这个客户端提供服务
- Follower 是 客户端
- Client 和 ZK 服务端之间的通信:有两种:NIO(默认实现) + Netty(需要通过配置来开启)
- 客户端:ClientCnxnSocketNIO,平白无奇的 NIO 的客户端
- 服务端:NIOServerCnxn,这个服务端服务组件,是通过 NIOServerCnxnFactory 工厂类来创建的,在这个类中,有一个 Listener 的组件,启动了一个NIO 的服务端,监听了 2181 端口,等待客户端发起链接请求,只要建立了链接,则 ZooKeeper Server 就会创建一个 NIOServerCnxn 专门负责给某一个Client 提供服务
ServerState
org.apache.zookeeper.server.quorum.QuorumPeer.ServerState
public enum ServerState {
LOOKING, // TODO 注释: 所有节点刚启动的时候的状态
FOLLOWING, // TODO 注释: 某个节点成为 follower 角色的时候的状态
LEADING,
OBSERVING
}
没有leader的时候,都是LOOKING状态
如果有leader的话,根据选举结果和配置信息,来决定自己的状态
区分三对概念:
选举配置:observer participant
集群角色:observer leader follower
服务器状态:LOOKING FOLLOWING LEADING OBSERVING
ZabState
org.apache.zookeeper.server.quorum.QuorumPeer.ZabState
public enum ZabState {
ELECTION, // TODO 注释: 表示正在选举
DISCOVERY, // TODO 注释: 选举算法工作完成,得到一个推举的结果,现在正在确认
SYNCHRONIZATION,
BROADCAST
}
选举算法工作的结果,只是当前这个节点得到一个推举的结果
不同节点得到的推举结果有可能不一样
需要确认:相互之间再次发送信息确认跟随的leader是否是同一个
如果确认了leader,则选举才真正结束
选举结束进入同步状态
同步状态结束之后,进入BROADCAST状态,
只有进入BROADCAST状态,才能接收和处理外部客户端的请求
启动过程中状态:ELECTION,DISCOVERY,SYNCHRONIZATION(也是崩溃恢复)
启动完成状态:BROADCAST(原子广播)
Zookeeper 内部的网络通信的具体实现
1、执行选举使用的是: BIO 通信(ServerSocket Socket)
2、ZooKeeper 作为一个 C/S 体系的软件,对外提供服务,是 NIO 实现
3、ZooKeeper 的 C/S 架构也提供了 netty 的实现,但是需要去配置才可可以实现。默认是就是 NIO
Java IO
百度搜索:五种 IO 模型
1、BIO JDK-1.1(编码简单,效率低) 阻塞模型
选举过程中,多个节点之间的相互通信使用的网络通信模型
2、NIO JDK-1.4(效率有提升,编码复杂) 基于reactor实现的异步非阻塞网络通信模型
通常的IO的选择:
原生NIO
基于NIO实现的网络通信框架:netty
3、AIO JDK-1.7(效率最高,编码复杂度一般) 真正的异步非阻塞通信模型
NIO 的三大API:
1、Buffer
2、Channel
3、Selector
ZooKeeper 内部在 3.4.14 版本以前都是使用的 单 selector 的实现!从 zookeeper-3.5.x 版本往后,采用了 一主(AcceptThread:OP_ACCEPT)多从(SelectorThread: OP_READ 和 OP_WRITE)的多线程 reactor 模式,事实上,真正完全数据读写工作,是一个线程池: WorkerThreaPool
ZooKeeper 中的服务端和客户端
1、服务端:QuorumPeer ===> 启动了 ServerCnxnFactory,启动了NIO服务端,监听了2181端口 ===> 接收到客户端的一个链接请求,则生成一个ServerCnxn,当该对象创建好之后,会为当前这个客户端建立成功的链接,创建一个 Session 对象。
2、客户端:ZooKeeper ===> 启动和初始化了一个 ClientCnxn(SendThread EventThread) 对线,发送 ConnectRequest 给服务端
关于客户端和服务端的一个定义:谁发请求,谁就是客户端,谁接收和处理请求,谁就是服务端
1、真正的 client 给 zookeeper 发请求
2、zookeeper 中的 leader 给 follower 发命令
3、zookeeper 中的 follower 给 leader 发请求
两个最重要的 API: C/S 架构模式
1、ServerCnxn 服务端的通信组件
zookeeper集群启动的时候,会初始化 ServerCnxn
2、ClientCnxn 客户端的通信组件
当编写代码:new ZooKeeper(1,2,3) 底层会初始化一个通信客户端对象
ServerCnxn:org.apache.zookeeper.server.ServerCnxn
Stats,表示ServerCnxn上的统计数据。
Watcher,表示事件处理,监听器。
ServerCnxn,表示服务器连接,表示一个从客户端到服务器的连接。
ClientCnxn,存在于客户端用来执行通信的组件。
NettyServerCnxn,基于Netty的连接的具体实现。
NIOServerCnxn,基于NIO的连接的具体实现。
ServerCnxnFactory, 服务端通信组件的工厂实现 也有两种: NIOServerCnxnFactory + NettyServerCnxnFactory