文档章节

ZooKeeper服务端单机版 ZooKeeperServer初始化源码分析

 没有脚印
发布于 2015/11/19 17:57
字数 1215
阅读 32
收藏 0

一.初始化ZooKeeperServer



1. ServerStats:统计服务器运行数据


2. FileTxnSnapLog
用于对服务器日志和数据进行操作。从配置文件读取,并初始化存储位置。
默认日志存储路径和数据一样。
3. ZKDatabase
用于存储数据,日志,sessionId,树结构DataTree
4.tickTime
public static final int DEFAULT_TICK_TIME = 3000;
protected int tickTime = DEFAULT_TICK_TIME;
默认是3秒,这里初始化的是配置文件的tickTime。
用处:
1)用于计算seesion最大,最小超时时间
protected int minSessionTimeout = -1;
protected int maxSessionTimeout = -1;
如果配置文件没设置,则最大超时时间为tickTime20倍,最小超时时间为tickTime 2倍


2)用于计算initLimit, syncLimit
initLimit* tickTime,syncLimit* tickTime

二.运行simple zookeeper server

在NIOServerCnxnFactory执行startup时,会对zookeeper server进行初始化


  初始化数据:

 public void startdata()

     throws  IOException, InterruptedException {
         //check to see if zkDb is not null
      //如果zkDb为空,则初始化
         if  ( zkDb  ==  null ) {
             zkDb  =  new  ZKDatabase( this . txnLogFactory );
        }
         //如果zkDb未加载完成,设置 zxid,杀死session,保存数据至disk(即清空snapshot)
         if  (! zkDb  .isInitialized()) {
            loadData();
        }

    }

初始化一些基本配置:



1创建session追踪器



session追踪器有4个重要属性
sessionsById: key:sessionId value:session
sessionsWithTimeout: key:sessionId value:过期时间
该属性会再每次addSession时改变
sessionExpryQueue: 时间整点的session队列,用于session过期检查
nextSessionId:下次createSession时sessionId为该数值+1
2.启动session追踪器:



下面是sessionExpiryQueue.poll()的代码



3. setupRequestProcessors()创建请求加工链
PrepRequestProcessor——> SyncRequestProcessor——>FinalRequestProcessor


PrepRequestProcessor:是一个阻塞自旋线程,对需要创建事物的请求创建事物,同时对session一些检查,run代码如下

SyncRequestProcessor: 自旋线程, 主要对事务请求进行日志记录,同时事务请求达到一定次数(超过 snapCount /2- snapCount之间的某一个值 )后,就会执行一次快照 代码如下
  @Override
     public  void  run() {
         try  {
             int  logCount  = 0;

             // we do this in an attempt to ensure that not all of the servers
             // in the ensemble take a snapshot at the same time
             int  randRoll  =  r  .nextInt( snapCount /2);
             while  ( true  ) {
                Request  si  =  null ;
                 //要输出数据为空则等待
                 if  ( toFlush  .isEmpty()) {
                     //processRequest(Request request) 时queuedRequests.add(request);
                     //单机版这儿为PrepRequestProcessor发送过来的request
                     si  =  queuedRequests .take();
                }  else  {
                     //poll()算法为非阻塞算法,立即返回或等待一会再返回
                     si  =  queuedRequests .poll();
                     //当期没有请求进来时
                     if  ( si  ==  null ) {
                          //提交所有遗留的request的日志,执行next.processRequest
                        flush(  toFlush );
                         continue ;
                    }
                }
                 if  ( si  ==  requestOfDeath  ) {
                     break ;
                }
                 if  ( si  !=  null ) {
                     // track the number of records written to the log
                     //记录写入日志记录写入日志的记录数,如果成功记录
                     //据说这步是区分是事物还是非事物,非事物返回false
                     if  ( zks  .getZKDatabase().append( si )) {
                         logCount ++;
                         //logCount>snapCount/2+(0-snapCount/2)
                         //这么做是为了所有服务器不再同一时间采用快照
                         if  ( logCount  > ( snapCount  / 2 +  randRoll )) {
                             randRoll  =  r .nextInt( snapCount  /2);
                             // roll the log
                             zks .getZKDatabase().rollLog();
                             // take a snapshot
                             if  ( snapInProcess  !=  null  &&  snapInProcess .isAlive()) {
                                 LOG .warn( "Too busy to snap, skipping" );
                            }  else  {
                               //保存数据
                                 snapInProcess  =  new  ZooKeeperThread( "Snapshot Thread"  ) {
                                         public  void  run() {
                                             try  {
                                                 zks .takeSnapshot();
                                            }  catch (Exception  e  ) {
                                                 LOG .warn( "Unexpected exception"  ,  e  );
                                            }
                                        }
                                    };
                                 snapInProcess .start();
                            }
                             logCount  = 0;
                        }
                    }  else  if  ( toFlush  .isEmpty()) {
                          //之前没有遗留请求,则执行下一个请求加工处理器
                         // optimization for read heavy workloads
                         // iff this is a read, and there are no pending
                         // flushes (writes), then just pass this to the next
                         // processor
                         if  ( nextProcessor  !=  null ) {
                             nextProcessor .processRequest( si  );
                             if  ( nextProcessor  instanceof  Flushable) {
                                ((Flushable) nextProcessor ).flush();
                            }
                        }
                         continue ;
                    }
                  
                     toFlush .add(  si );      
                     //遗留请求超过1000时,对遗留请求进行处理,还有一个处理是,再上面开头
                     //上面开头。当前没有请求进来时,对遗留请求进行处理
                     if  ( toFlush  .size() > 1000) {
                          //提交所有遗留的request日志,执行next.processRequest
                        flush(  toFlush );
                    }
                }
            }
        }  catch  (Throwable  t  ) {
            handleException(  this .getName(),  t  );
        }  finally {
             running  =  false ;
        }
         LOG .info( "SyncRequestProcessor exited!"  );
    }
主要操作:
1.自旋操作
2.判断未写入日志请求 toFlush 是否为空 ,若为空,则阻塞等待新的请求,若不为空,则非阻塞获取请求,若无请求可获取,则写入日志
3.收到死亡请求跳出自旋
4.如果是事物请求,zkdatabase添加日志,并判断日志数量 logCount是否达到snapCount(发生几次snapCount,就会执行一次快照)/2+0到snapCount/2 次数,若达到,生成数据快照
为什么会有个区间,是为了避免,所有服务器同一时间写入日志
5.如果非事物,若 toFlush为空,则执行下一个请求加工处理器。
6.若都不是,则把request添加至 toFlush,等待写入日志

FinalRequestProcessor:对request进行主要处理,前面两个一个是添加食物,相关检查。另外一个是记录request日志和一定时间点存储数据。
FinalRequestProcessor主要操作:
1.增删改DataTree
2.新增或关闭session
3. 移除  List<ChangeRecord>outstandingChanges, zxid<  当前 zxid   ChangeRecord 数据,同时移除相对应  outstandingChangesForPath
4.如果是集群: zks .getZKDatabase(). addCommittedProposal(  request  )
5.   如果 request.type   closeSession, 关闭  ServerCnxnFactory  里对应的 seesionId,return.
6.  根据不同 request.type,  准备返回值  response

代码太行。。就不贴了。

PS:文本编辑器好难用

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 2
码字总数 1551
作品 0
厦门
程序员
私信 提问
ZooKeeper源码研究系列(3)单机版服务器介绍

1 系列目录 - ZooKeeper源码研究系列(1)源码环境搭建- ZooKeeper源码研究系列(2)客户端创建连接过程分析- ZooKeeper源码研究系列(3)单机版服务器介绍- ZooKeeper源码研究系列(4)集群...

乒乓狂魔
2015/08/13
0
0
SkyWalking 源码分析系列 —— Collector Cluster 集群管理

name="小幸运" singer="田馥甄 - 湘江音乐节" playlength="250" src="/cgi-bin/readtemplate?t=tmpl/qqmusictmpl&singer=%E7%94%B0%E9%A6%A5%E7%94%84%20-%20%E6%B9%98%E6%B1%9F%E9%9F%B3%E......

工匠小猪猪的技术世界
2018/06/28
0
0
ZooKeeper源码研究系列(1)源码环境搭建

1 系列目录 - ZooKeeper源码研究系列(1)源码环境搭建- ZooKeeper源码研究系列(2)客户端创建连接过程分析- ZooKeeper源码研究系列(3)单机版服务器介绍- ZooKeeper源码研究系列(4)集群...

乒乓狂魔
2015/07/29
0
4
ZooKeeper基本讲解 & 集群构建 & 常用操作指令

一、ZooKeeper概述 ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,是Google的Chubby一个开源实现,是Hadoop和Hbase的重要组件,它提供了一项基本服务:分布式锁服...

qw87112
2018/06/28
0
0
ZooKeeper源码研究系列(2)客户端创建连接过程分析

1 系列目录 - ZooKeeper源码研究系列(1)源码环境搭建- ZooKeeper源码研究系列(2)客户端创建连接过程分析- ZooKeeper源码研究系列(3)单机版服务器介绍- ZooKeeper源码研究系列(4)集群...

乒乓狂魔
2015/08/03
0
4

没有更多内容

加载失败,请刷新页面

加载更多

前端、后端和全栈到底不该学什么

1、前言 在职业规划咨询过程中经常会被问到这样的问题: 老师,我是该深入钻研专精一门,走技术大牛路线,还是所有都要精通,做一个全栈工程师? 类似问题的变种还有,老师我是不是该30岁最迟...

前端攻城小牛
28分钟前
3
0
【git命令】git-stash

应用场景 应用场景:使用git的时候,我们往往使用branch解决任务切换问题,例如,我们往往会建一个自己的分支去修改和调试代码, 如果别人或者自己发现原有的分支上有个不得不修改的bug,我们...

echojson
30分钟前
2
0
centos7.3编译安装OpenSSL1.1.1b

简介 OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。 安装 下载:下载地址 ...

阿dai学长
31分钟前
1
0
0基础【转行】大数据

目前大数据行业异常火爆,不少人都对大数据充满了兴趣,其中有大部分人都是之前没有接触过计算机技术的,对编程语言也不太了解,那是不是这部分零基础的朋友就学不了大数据了呢?答案当然是否...

董黎明
32分钟前
1
0
Krpano 动态传参-action

效果解释:点击热点1,触发显示或隐藏热线2。 hotspot等标签允许编写自定义属性,这里直接设置自定义属性为dk=spot6,点击spot7,显示或隐藏spot6。 action方法体中,直接引用get(dk)即可获得...

华山猛男
38分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部