zookeeper源码学习一——zookeeper启动
最近正在研究zookeeper,一些心得记录一下,如有错误,还请大神指正。
zookeeper下载地址:http://zookeeper.apache.org/releases.html,百度一下就能找到,不过还是在这里列一下。
我认为学习一个东西,首先要理出一个头绪,否则感觉无从下手,这里我从启动开始研究,即从zkSever.sh入手。
if [ "x$JMXDISABLE" = "x" ]
then
echo "JMX enabled by default" >&2
# for some reason these two options are necessary on jdk6 on Ubuntu
# accord to the docs they are not necessary, but otw jconsole cannot
# do a local attach
ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain"
else
echo "JMX disabled by user request" >&2
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
fi
从zkSever.sh可以看出,启动入口在QuorumPeerMain中,源码如下:
// 入口函数
public static void main(String[] args)
{
QuorumPeerMain main = new QuorumPeerMain();
//...1、启动初始化
main.initializeAndRun(args);
// ...
} protected void initializeAndRun(String[] args)
throws QuorumPeerConfig.ConfigException, IOException
{
// 2、加载配置文件
QuorumPeerConfig config = new QuorumPeerConfig();
if (args.length == 1) {
// 解析配置文件
config.parse(args[0]);
} if ((args.length == 1) && (config.servers.size() > 0)) {
// 配置文件的信息加载至QuorumPeer
runFromConfig(config);
} else {
LOG.warn("Either no config or no quorum defined in config, running in standalone mode"); ZooKeeperServerMain.main(args);
}
} public void runFromConfig(QuorumPeerConfig config) throws IOException {
try {
ManagedUtil.registerLog4jMBeans();
} catch (JMException e) {
LOG.warn("Unable to register log4j JMX control", e);
} LOG.info("Starting quorum peer");
try {
NIOServerCnxn.Factory cnxnFactory = new NIOServerCnxn.Factory(config.getClientPortAddress(), config.getMaxClientCnxns()); // 3、启动QuorumPeer
this.quorumPeer = new QuorumPeer();
this.quorumPeer.setClientPortAddress(config.getClientPortAddress());
//...加载各种配置信息 this.quorumPeer.start();
this.quorumPeer.join();
}
catch (InterruptedException e) {
LOG.warn("Quorum Peer interrupted", e);
}
}
可以看出,配置文件的解析由QuorumPeerConfig 类完成,其部分源码如下:
public void parse(String path)
throws QuorumPeerConfig.ConfigException
{
File configFile = new File(path); LOG.info("Reading configuration from: " + configFile);
try
{
if (!configFile.exists()) {
throw new IllegalArgumentException(configFile.toString() + " file is missing");
}
// 将配置信息加载如property文件
Properties cfg = new Properties();
FileInputStream in = new FileInputStream(configFile);
try {
cfg.load(in);
} finally {
in.close();
} parseProperties(cfg);
} catch (IOException e) {
throw new ConfigException("Error processing " + path, e);
} catch (IllegalArgumentException e) {
throw new ConfigException("Error processing " + path, e);
}
} public void parseProperties(Properties zkProp)
throws IOException, QuorumPeerConfig.ConfigException
{
int clientPort = 0;
String clientPortAddress = null;
// 循环解析配置文件
for (Map.Entry entry : zkProp.entrySet()) {
String key = entry.getKey().toString().trim();
String value = entry.getValue().toString().trim();
if (key.equals("dataDir")) {
this.dataDir = value;
} else if (key.equals("dataLogDir")) {
this.dataLogDir = value;
} else if (key.equals("clientPort")) {
// 客户端连接的端口号
clientPort = Integer.parseInt(value);
} else if (key.equals("clientPortAddress")) {
clientPortAddress = value.trim();
} else if (key.equals("tickTime")) {
// 心跳时间
this.tickTime = Integer.parseInt(value);
} else if (key.equals("maxClientCnxns")) {
this.maxClientCnxns = Integer.parseInt(value);
} else if (key.equals("minSessionTimeout")) {
this.minSessionTimeout = Integer.parseInt(value);
} else if (key.equals("maxSessionTimeout")) {
this.maxSessionTimeout = Integer.parseInt(value);
} else if (key.equals("initLimit")) {
this.initLimit = Integer.parseInt(value);
} else if (key.equals("syncLimit")) {
this.syncLimit = Integer.parseInt(value);
} else if (key.equals("electionAlg")) {
// 选举算法的类型,默认算法为FastLeaderElection
this.electionAlg = Integer.parseInt(value);
} else if (key.equals("peerType")) {
if (value.toLowerCase().equals("observer"))
this.peerType = QuorumPeer.LearnerType.OBSERVER;
else if (value.toLowerCase().equals("participant")) {
this.peerType = QuorumPeer.LearnerType.PARTICIPANT;
}
else
throw new ConfigException("Unrecognised peertype: " + value);
}
//...
回到QuorumPeerMain类的runFromConfig方法。此方法中,会将配置信息加载至QuorumPeer,并调用其start方法:
public synchronized void start()
{
try {
this.zkDb.loadDataBase();
} catch (IOException ie) {
LOG.fatal("Unable to load database on disk", ie);
throw new RuntimeException("Unable to run quorum server ", ie);
}
this.cnxnFactory.start();
startLeaderElection();
super.start();
}
在start方法中,会现价在硬盘中的数据,
this.zkDb.loadDataBase();即ZKDatabase中
public long loadDataBase()
throws IOException
{
FileTxnSnapLog.PlayBackListener listener = new FileTxnSnapLog.PlayBackListener() {
public void onTxnLoaded(TxnHeader hdr, Record txn) {
Request r = new Request(null, 0L, hdr.getCxid(), hdr.getType(), null, null); r.txn = txn;
r.hdr = hdr;
r.zxid = hdr.getZxid();
ZKDatabase.this.addCommittedProposal(r);
}
};
long zxid = this.snapLog.restore(this.dataTree, this.sessionsWithTimeouts, listener);
this.initialized = true;
return zxid;
}
然后开确定选类型,startLeaderElection
public synchronized void startLeaderElection() {
this.currentVote = new Vote(this.myid, getLastLoggedZxid());
for (QuorumServer p : getView().values()) {
if (p.id == this.myid) {
this.myQuorumAddr = p.addr;
break;
}
}
if (this.myQuorumAddr == null) {
throw new RuntimeException("My id " + this.myid + " not in the peer list");
}
if (this.electionType == 0) {
try {
this.udpSocket = new DatagramSocket(this.myQuorumAddr.getPort());
this.responder = new ResponderThread();
this.responder.start();
} catch (SocketException e) {
throw new RuntimeException(e);
}
}
this.electionAlg = createElectionAlgorithm(this.electionType);//加载选举类型
}
然后启动run方法
zookeeper源码学习一——zookeeper启动的更多相关文章
- 菜鸟系列Fabric源码学习 — peer节点启动
Fabric 1.4 源码分析peer节点启动 peer模块采用cobra库来实现cli命令. Cobra提供简单的接口来创建强大的现代化CLI接口,比如git与go工具.Cobra同时也是一个程序, ...
- SpringBoot源码学习系列之启动原理简介
本博客通过debug方式简单跟一下Springboot application启动的源码,Springboot的启动源码是比较复杂的,本博客只是简单梳理一下源码,浅析其原理 为了方便跟源码,先找个Ap ...
- Zookeeper 源码学习(一)环境搭建
前言 最近准备学习 Zookeeper,想从 Zookeeper 开始逐步深入了解各类中间件,学习分布式计算. 下载源码 执行指令,下载代码: git clone https://github.com ...
- ASP.NET Core MVC 源码学习:MVC 启动流程详解
前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...
- zookeeper源码 — 一、单机启动
zookeeper一般使用命令工具启动,启动主要就是初始化所有组件,让server可以接收并处理来自client的请求.本文主要结构: main入口 配置解析 组件启动 main入口 我们一般使用命令 ...
- ABP 框架从源码学习——abp框架启动和结束(1)
1.abp框架的启动是从Global.asax文件的Application_Start启动的,当然代表Global的application必须从AbpWebApplication继承: publ ...
- ThinkPHP5.0源码学习之框架启动流程
ThinkPHP5框架的启动流程图如下: ThinkPHP5的启动流程按照文件分为三步: 1.请求入口(public/index.php) 2.框架启动(thinkphp/start.php) 3.应 ...
- 菜鸟系列Fabric源码学习—orderer服务启动
Fabric 1.4 orderer 服务启动流程 1.提要 orderer提供broadcast和deliver两个服务接口.orderer节点与各个peer节点通过grpc连接,orderer将所 ...
- ABP 框架从源码学习——abp框架启动核心类AbpBootstrapper(2)
在AbpBootstrapper中的两个至关重要的属性:IIocManager 和 IAbpModuleManager public class AbpBootstrapper : IDisposa ...
随机推荐
- 学习php前需要了解的知识
1.静态网站与动态网站 A)静态网站: 不支持数据交互的网站(后缀: .html .htm) B)动态网站: 支持数据交互的网站,动态网站可以放静态网页的 i.实现动态网站的技术 1.Asp ...
- 练手CF3-C - Wormhouse
深搜,亮点在那个剪枝,flag代表是否搜索数组从开始到当前一直等于原始数组同位置的数,如果是真,就从原始数组的当前位置的书开始搜,否则就从0开始搜. 见代码. #include <iostrea ...
- HDU 1622
http://acm.hdu.edu.cn/showproblem.php?pid=1622 白书上6.3.2二叉树层次遍历的例题,层次遍历用bfs,建立二叉树,很基础的题目 #include < ...
- javascript:;与javascript:void(0)使用介绍
有时候我们在编写js过程中,需要触发事件而不需要返回值,那么就可能需要这样的写法 href=”#”,包含了一个位置信息.默认的锚是#top,也就是网页的上端,当连续快速点击此链接时会导致浏览器巨慢甚至 ...
- FSM
一.状态机简单介绍 软件设计中的状态机概念,一般是指有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和 ...
- ASP.NET定制简单的错误处理页面
通常Web应用程序在发布后,为了给用户一个友好界面和使用体验,都会在错误发生时跳转至一个自定义的错误页面,而不是ASP.net向用户暴露出来的详细的异常列表. 简单的错误处理页面可以通过web.con ...
- Openstack学习历程_1_视频
学习视频:讲解Openstack每个模块对应的作用
- Ubuntu sudo NOPASSWD设置
1.首先查看目标用户的信息,包括所属组: ◄► id cason uid=(cason) gid=(cason) (cason),(adm),(cdrom),((dip),(plugdev),(lpa ...
- Core Java Volume I — 3.6. Strings
3.6. StringsConceptually, Java strings are sequences of Unicode characters(Java的字符串是一个Unicode序列). Fo ...
- ZOJ 1002 Fire Net
题目大意:有一个4*4的城市,其中一些格子有墙(X表示墙),在剩余的区域放置碉堡.子弹不能穿透墙壁.问最多可以放置几个碉堡,保证它们不会相互误伤. 解法:从左上的顶点开始遍历,如果这个点不是墙,做深度 ...