今天主要是说源码的分析,客户端启动过程的源码分析和服务端启动过程的源码分析。最后在说说zookeeper的运维和总结。源码:https://github.com/limingios/netFuture/源码/『互联网架构』软件架构-zookeeper之源码分析和运维总结(37)
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_1_20190501080621516)
(一)服务的启动过程![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_2_20190501080621813)
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_3_20190501080622250)
如何选举出来的,两种方式
1.jps查看
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_4_20190501080622657)
2.vim zkServer.sh
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_5_2019050108062316) 为了保证写操作的一致性与可用性。
zookeeper专门设计了一种名为原子广播(ZAB)的支持崩溃恢复的一致性协议,基于该协议,zookeeper实现了一种主从模式的系统架构来保持集群中各个副本之间的数据一致性
根据ZAB协议,所有的写操作都必须通过Leader完成,Leader写入本地日常后再复制到所有的Follower节点。
一旦Leader节点无法工作,ZAB协议能够自动从Follower节点中重新选出一个合适的替代者,即新的Leader,该过程即为领导选举,该领导选举过程,是ZAB协议中最为重要和复杂的过程。FastLeaderElection是Fast Paxos算法实现。
3.查看QuorumPeerMain
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_6_20190501080623719) QuorumPeerConfig调用这个方法的parse方法
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_7_20190501080624391)
加载配置文件FileInputStream,load
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_8_20190501080624875)
load 加载load0
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_9_20190501080625407)
在家配置文件的时候,parseProperties,看到里面获取的关键字,是不是有点惊喜,是不是对应咱们的zoo.cfg文件,获取到之后给属性赋值。
![](http://image109.360doc.com/DownloadImg/2019/05/0120/160180019_10_20190501080626110)
![](http://pubimage.360doc.com/wz/default.gif)
主类的start方法
![](http://pubimage.360doc.com/wz/default.gif)
1.loadDataBase 启动时先从内存数据库中恢复数据
2.cnxnFactrory.start() 通过NIO的方式读和写的操作,启动socker编程
3.startLeaderElection 选举算法,选择出来的leader
![](http://pubimage.360doc.com/wz/default.gif)
4.涉及到的算法,zab和Paxos算法,zab是实践算法(依赖了Paxos的思想做了简化),Paxos属于理论的算法(美国总统竞选的一个过程)。具体Paxos理论:参考源码:里面的文档。start 就是启动开始干活了。
注意
Leader 不需要得到所有Follower的ACK,只要收到过半的ACK即可,同时Leader本身对自己有的一个ACK Observer虽然没有投票权,但仍须同步Leader的数据从而在处理读请求时,可以返回竟可能新的数据。
![](http://pubimage.360doc.com/wz/default.gif)
默认的没有observer 如何设置
在zoo.cfg中选择一个节点后面添加:obServer
![](http://pubimage.360doc.com/wz/default.gif)
![](http://pubimage.360doc.com/wz/default.gif)
既然obServer没有投票权,在实际使用中,如果机器比较多允许的话,建议增加一个obServer,不进行投票减少资源的消耗,还能负载减轻其他机器的压力。这就是古代皇宫的太监,能干活还放心,没有话语权,只会干活。
(二)客户的启动过程![image.png](http://pubimage.360doc.com/wz/default.gif)
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,boolean canBeReadOnly) throws IOException
{
LOG .info( "Initiating client connection, connectString=" + connectString
+ " sessionTimeout=" + sessionTimeout + " watcher=" + watcher);
watchManager. defaultWatcher = watcher;
ConnectStringParser connectStringParser = new ConnectStringParser(
connectString);
HostProvider hostProvider = new StaticHostProvider(
connectStringParser.getServerAddresses());//拿到 ip 端口号
cnxn = new ClientCnxn(connectStringParser.getChrootPath(),
hostProvider, sessionTimeout, this, watchManager,
getClientCnxnSocket (), canBeReadOnly);//创建 ClientCnxn 对象
cnxn.start();//非 thread 线程启动
}
public ClientCnxn(String chrootPath, HostProvider hostProvider, int
sessionTimeout, ZooKeeper zooKeeper,ClientWatchManager watcher, ClientCnxnSocket clientCnxnSocket,long sessionId, byte[] sessionPasswd, boolean canBeReadOnly) {
this. zooKeeper = zooKeeper;
this. watcher = watcher;
this. sessionId = sessionId;
this. sessionPasswd = sessionPasswd;
this. sessionTimeout = sessionTimeout;
this. hostProvider = hostProvider;
this. chrootPath = chrootPath;
connectTimeout = sessionTimeout / hostProvider.size();
readTimeout = sessionTimeout * 2 / 3;
readOnly = canBeReadOnly;
sendThread = new SendThread(clientCnxnSocket);
eventThread = new EventThread();
}
用户发送一个读取数据节点的请求,该请求首先被封装成一个相应类型的数据包放入outgoingQueue队列中,sendThread会把数据包从队列中取出然后发往服务端并把该数据包加入到pendingQueue中,当sendThread收到服务端响应时,会与pendingQueue队列中的第一个数据包进行对比,判断是否是期待的那个响应包(这里可以看出数据包是串行处理的),最后把响应的数据包封装成对应类型的事件加入到waitingEvents中,再由eventThread取出进行处理。
(三)运维相关![](http://pubimage.360doc.com/wz/default.gif)
![](http://pubimage.360doc.com/wz/default.gif)
echo conf|nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
输出指定server上所有客户端连接的详细信息,包括客户端IP,会话ID等
连接信息的总览,连接ip、端口号、该连接的发包数、该连接的收包数、连接的session Id、最后操作方式/命令、连接的时间戳、超时时间(未确认)、最后的zxid、最后、响应时间戳、连接的时间延时信息等
echo cons|nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
功能性命令。重置所有连接的统计信息
“` bash·
echo crst|nc localhost 2181
![](https://upload-images./upload_images/11223715-f4ab65e662d98cd3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>针对Leader执行,用于输出所有等待队列中的会话和临时节点的信息
``` bash
echo dump|nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
输出server简要状态和连接的客户端信息
echo stat|nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
列出所有watcher信息,以watcher的session为归组单元排列,列出该会话订阅了哪些path。
echo wchc|nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
输出一些ZK运行时信息
版本、延时、收包、发包、连接数、未完成客户端请求数、leader/follower 状态、znode 数、watch 数、临时节点数、近似数据大小 应该是一个总和的值、打开文件描述符 数、最大文件描述符数、fllower数等等
echo mntr | nc localhost 2181
![](http://pubimage.360doc.com/wz/default.gif)
![](http://pubimage.360doc.com/wz/default.gif)
PS:zookeeper就告一段落了,zookeeper互联网的奠基石,这个一定要理解原理,有基本的使用,架构之路必须要翻越的一面墙
|