Zookeeper集群启动配置
1、配置文件
创建三个配置文件conf\zoo_sample.cfg、conf\zoo_sample2.cfg、conf\zoo_sample3.cfg
只有dataDir和clientPort对应不同的服务端数据存储位置及客户端连接端口
在dataDir文件夹下需要分别创建myid文件,用来存储server后面的序号1、2、3。(例如server.1=127.0.0.1:12881:13881的1)
2、三个服务端
QuorumPeerMain对应conf\zoo_sample.cfg启动
QuorumPeerMain3对应conf\zoo_sample3.cfg启动
QuorumPeerMain2对应conf\zoo_sample2.cfg启动
3、两个客户端配置
加个 -D:zoocfg=D:\workspase\zookeeper-master\conf\zoo_sample.cfg 对于不同服务端的客户端(对应不同端口)连接
集群启动
1、isDistributed判断是否以集群方式启动
org.apache.zookeeper.server.quorum.QuorumPeerConfig#isDistributed
standaloneEnabled=true(默认是false,是非集群)也可以启动
votingMembers参与投票数量大于1,也是集群启动。
可以算出过半值half=1(当以三台启动3/2=1)
2、initializeAndRun初始化集群
org.apache.zookeeper.server.quorum.QuorumPeerMain#initializeAndRun
这里便是根据isDistributed来判断是否以集群启动,与单机启动的区别
3、runFromConfig
org.apache.zookeeper.server.quorum.QuorumPeerMain#runFromConfig
①、ServerCnxnFactory创建与单机相同
②、创建quorumPeer对象,并给参数赋值
创建quorumPeer对象,并给参数赋值。从config读取到quorumPeer中,下面是对myid赋值
③、quorumPeer.start 启动
initialize 初始化、JvmPauseMonitor赋值、start 启动、join 阻塞
4、QuorumPeer#start
org.apache.zookeeper.server.quorum.QuorumPeer#start
主要步骤:
①、loadDataBase()加载数据
②、startServerCnxnFactory 用来开启acceptThread、SelectorThread和workerPool线程池
③、开启领导者选举startLeaderElection
④、开启JVM监控线程startJvmPauseMonitor
⑤、调用父类super.start();进行领导者选举
初始化领导者选举相关的线程和队列
1、startLeaderElection
①、创建当前选票currentVote
②、创建选举方式createElectionAlgorithm
2、createElectionAlgorithm
org.apache.zookeeper.server.quorum.QuorumPeer#createElectionAlgorithm
目前选举方式只有electionAlgorithm=3
这个方法创建了以下三个对象:
①、创建QuorumCnxManager对象
②、QuorumCnxManager.Listener
③、FastLeaderElection
1、创建QuorumCnxManager对象
这个类是一个使用TCP实现用于领导者选举的连接管理器类。可以简单理解为一个处理Socket的传输层类
org.apache.zookeeper.server.quorum.QuorumCnxManager#QuorumCnxManager
创建recvQueue、queueSendMap、senderWorkerMap等属性对象
2、创建QuorumCnxManager.Listener对象
Listener的创建和启动
a、run
org.apache.zookeeper.server.quorum.QuorumCnxManager.Listener#run
b、启动ListenerHandler线程
org.apache.zookeeper.server.quorum.QuorumCnxManager.Listener.ListenerHandler#run
c、acceptConnections
org.apache.zookeeper.server.quorum.QuorumCnxManager.Listener.ListenerHandler#acceptConnections
开启服务端serverSocket,等待客户端连接。阻塞在serverSocket.accept()方法
服务端间的连接
当再开一台,则会进行相互连接。阻塞在serverSocket.accept()的方法这里将会继续往下执行。13881和13883端口用来进行领导者选举。
server.1=127.0.0.1:12881:13881
server.3=127.0.0.1:12883:13883
表示:由sid=1的向sid=3的连接,则会关闭当前sid=1连接的sid=3的socket。sid=3的会向sid=1进行连接
1、acceptConnections
接受连接
org.apache.zookeeper.server.quorum.QuorumCnxManager.Listener.ListenerHandler#acceptConnections
2、receiveConnection
处理连接
org.apache.zookeeper.server.quorum.QuorumCnxManager#receiveConnection
3、handleConnection
org.apache.zookeeper.server.quorum.QuorumCnxManager#handleConnection
①、通过网络连接获取数据sid,获取sid表示是那一台连过来的
②、关闭小的sid向大的sid的socket连接
如果当前sid比连过来的大(sid < self.getId()表示当前sid=3的是服务端),由sid=1的向sid=3的连接,则会关闭当前sid=1连接的sid=3的socket。上图所示。
③、大的sid与小的sid建立socket连接(服务端是小的sid=1)
关闭sid=1向sid=3的socket后,建立sid=3向sid=1建立连接(即大的sid向小的sid连接)
4、connectOne 主动建立socket连接
org.apache.zookeeper.server.quorum.QuorumCnxManager#connectOne
5、initiateConnectionAsync
org.apache.zookeeper.server.quorum.QuorumCnxManager#initiateConnectionAsync
6、执行QuorumConnectionReqThread线程run方法
org.apache.zookeeper.server.quorum.QuorumCnxManager#initiateConnection
7、initiateConnection
建立socket连接
org.apache.zookeeper.server.quorum.QuorumCnxManager#initiateConnection
8、startConnection
org.apache.zookeeper.server.quorum.QuorumCnxManager#startConnection
开启SendWorker、RecvWorker线程。并把SendWorker与sid放入到senderWorkerMap。创建queueSendMap集合
9、SendWorker#run
org.apache.zookeeper.server.quorum.QuorumCnxManager.SendWorker#run
从queueSendMap获取并发送给其他服务
org.apache.zookeeper.server.quorum.QuorumCnxManager.SendWorker#send
10、RecvWorker#run
org.apache.zookeeper.server.quorum.QuorumCnxManager.RecvWorker#run
读取并添加到recvQueue
3、创建FastLeaderElection对象
1、FastLeaderElection
org.apache.zookeeper.server.quorum.FastLeaderElection#FastLeaderElection
2、starter
org.apache.zookeeper.server.quorum.FastLeaderElection#starter
创建sendqueue、recvqueue队列。Messenger对象
3、Messenger
org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger#Messenger
创建WorkerSender并封装成wsThread线程,创建WorkerReceiver并封装成wrThread
4、FastLeaderElection#start
org.apache.zookeeper.server.quorum.FastLeaderElection#start
5、Messenger#start
org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger#start
启动WorkerSender和WorkerReceiver
6、WorkerSender#run
org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger.WorkerSender#run
从sendqueue发送队列取出并处理
org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger.WorkerSender#process
自己发送给自己选票
org.apache.zookeeper.server.quorum.QuorumCnxManager#addToRecvQueue
添加到recvQueue
7、WorkerReceiver#run
org.apache.zookeeper.server.quorum.FastLeaderElection.Messenger.WorkerReceiver#run
从recvQueue获取得到Message response对象
把发送给其他节点的投票信息封装成ToSend对象放入到sendqueue队列
总结:
本章主要分析了领导者选举的初始化。
在初始化过程中,主要创建了三个对象
1、QuorumCnxManager 这个类的创建的作用是创建与Socket底层交互的相关线程和队列
SendWorker和RecvWorker线程,recvQueue队列、queueSendMap和senderWorkerMap集合。
2、QuorumCnxManager.Listener 用来处理领导者选举的服务端的连接
3、FastLeaderElection 快速领导者选举工具类,创建了与领导者选举相关的线程和集合
WorkerSender和WorkerReceiver线程,sendqueue和recvqueue队列