zookeeper启动流程简单梳理
等着測试童鞋完工,顺便里了下zookeeper的启动流程
zk3.4.6
启动脚本里面
nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \ -cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
翻译过来之后太烦了,shit
java -Dzookeeper.log.dir=. -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/local/luping/zookeeper-3.4.6/bin/../build/classes:/usr/local/luping/zookeeper-3.4.6/bin/../build/lib/*.jar:/usr/local/luping/zookeeper-3.4.6/bin/../lib/slf4j-log4j12-1.6.1.jar:/usr/local/luping/zookeeper-3.4.6/bin/../lib/slf4j-api-1.6.1.jar:/usr/local/luping/zookeeper-3.4.6/bin/../lib/netty-3.7.0.Final.jar:/usr/local/luping/zookeeper-3.4.6/bin/../lib/log4j-1.2.16.jar:/usr/local/luping/zookeeper-3.4.6/bin/../lib/jline-0.9.94.jar:/usr/local/luping/zookeeper-3.4.6/bin/../zookeeper-3.4.6.jar:/usr/local/luping/zookeeper-3.4.6/bin/../src/java/lib/*.jar:/usr/local/luping/zookeeper-3.4.6/bin/../conf:.:/data/java/jdk1.7.0_15/jre/lib/rt.jar:/data/java/jdk1.7.0_15/lib/dt.jar:/data/java/jdk1.7.0_15/lib/tools.jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain
/usr/local/luping/zookeeper-3.4.6/bin/../conf/zoo.cfg
这里看到启动入口是QuorumPeerMain,先看其main()函数关键代码
QuorumPeerMain main = new QuorumPeerMain();
main.initializeAndRun(args);
initializeAndRun()这样的会启动单例还是集群模式的zookeeper
protected void initializeAndRun(String[] args)
throws ConfigException, IOException
{
QuorumPeerConfig config = new QuorumPeerConfig();
if (args.length == 1) {
config.parse(args[0]);
}
// Start and schedule the the purge task
DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
.getDataDir(), config.getDataLogDir(), config
.getSnapRetainCount(), config.getPurgeInterval());
purgeMgr.start();
if (args.length == 1 && config.servers.size() > 0) {
runFromConfig(config);
} else {
LOG.warn("Either no config or no quorum defined in config, running "
+ " in standalone mode");
// there is only server in the quorum -- run as standalone
ZooKeeperServerMain.main(args);
}
}
这里假设是集群模式走runFromConfig,首先注冊Mxbean
ManagedUtil.registerLog4jMBeans();
然后是初始化连接工厂。默认使用NIO,这里是NIOServerCnxnFactory
ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();
cnxnFactory.configure(config.getClientPortAddress(),
config.getMaxClientCnxns());
static public ServerCnxnFactory createFactory() throws IOException {
String serverCnxnFactoryName =
System.getProperty(ZOOKEEPER_SERVER_CNXN_FACTORY);
if (serverCnxnFactoryName == null) {
serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();
}
try {
return (ServerCnxnFactory) Class.forName(serverCnxnFactoryName)
.newInstance();
} catch (Exception e) {
IOException ioe = new IOException("Couldn't instantiate "
+ serverCnxnFactoryName);
ioe.initCause(e);
throw ioe;
}
}
z之后初始化QuorumPeer,进行对应的配置,最后启动QuorumPeer
ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();
cnxnFactory.configure(config.getClientPortAddress(),
config.getMaxClientCnxns());
quorumPeer = new QuorumPeer();
quorumPeer.setClientPortAddress(config.getClientPortAddress());
quorumPeer.setTxnFactory(new FileTxnSnapLog(
new File(config.getDataLogDir()),
new File(config.getDataDir())));
quorumPeer.setQuorumPeers(config.getServers());
quorumPeer.setElectionType(config.getElectionAlg());
quorumPeer.setMyid(config.getServerId());
quorumPeer.setTickTime(config.getTickTime());
quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout());
quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout());
quorumPeer.setInitLimit(config.getInitLimit());
quorumPeer.setSyncLimit(config.getSyncLimit());
quorumPeer.setQuorumVerifier(config.getQuorumVerifier());
quorumPeer.setCnxnFactory(cnxnFactory);
quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory()));
quorumPeer.setLearnerType(config.getPeerType());
quorumPeer.setSyncEnabled(config.getSyncEnabled());
quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs());
quorumPeer.start();
quorumPeer.join();
ServerCnxnFactory.configure()这里配置ServerSocketChannel
public void configure(InetSocketAddress addr, int maxcc) throws IOException {
configureSaslLogin();
thread = new Thread(this, "NIOServerCxn.Factory:" + addr);
thread.setDaemon(true);
maxClientCnxns = maxcc;
this.ss = ServerSocketChannel.open();
ss.socket().setReuseAddress(true);
LOG.info("binding to port " + addr);
ss.socket().bind(addr);
ss.configureBlocking(false);
ss.register(selector, SelectionKey.OP_ACCEPT);
}
QuorumPeer.start()
public synchronized void start() {
loadDataBase();
cnxnFactory.start();
startLeaderElection();
super.start();
}
1,首先载入数据 loadDataBase();
2。启动NIO线程;
3,启动leader选举
首先看从本地载入数据loadDataBase();
public long loadDataBase() throws IOException {
PlayBackListener listener=new PlayBackListener(){
public void onTxnLoaded(TxnHeader hdr,Record txn){
Request r = new Request(null, 0, hdr.getCxid(),hdr.getType(),
null, null);
r.txn = txn;
r.hdr = hdr;
r.zxid = hdr.getZxid();
addCommittedProposal(r);
}
};
long zxid = snapLog.restore(dataTree,sessionsWithTimeouts,listener);
initialized = true;
return zxid;
}
从zk的事务日志snapLog中恢复
long zxid = snapLog.restore(dataTree,sessionsWithTimeouts,listener);
之后会回调PlayBackListener的onTxnLoaded来onTxnLoaded提交Proposal(addCommittedProposal())
public long restore(DataTree dt, Map<Long, Integer> sessions,
PlayBackListener listener) throws IOException {
snapLog.deserialize(dt, sessions);
FileTxnLog txnLog = new FileTxnLog(dataDir);
TxnIterator itr = txnLog.read(dt.lastProcessedZxid+1);
long highestZxid = dt.lastProcessedZxid;
TxnHeader hdr;
try {
while (true) {
// iterator points to
// the first valid txn when initialized
hdr = itr.getHeader();
if (hdr == null) {
//empty logs
return dt.lastProcessedZxid;
}
if (hdr.getZxid() < highestZxid && highestZxid != 0) {
LOG.error("{}(higestZxid) > {}(next log) for type {}",
new Object[] { highestZxid, hdr.getZxid(),
hdr.getType() });
} else {
highestZxid = hdr.getZxid();
}
try {
processTransaction(hdr,dt,sessions, itr.getTxn());
} catch(KeeperException.NoNodeException e) {
throw new IOException("Failed to process transaction type: " +
hdr.getType() + " error: " + e.getMessage(), e);
}
listener.onTxnLoaded(hdr, itr.getTxn());
if (!itr.next())
break;
}
} finally {
if (itr != null) {
itr.close();
}
}
return highestZxid;
}
启动NIOServerCnxnFactory的start()
public void start() {
// ensure thread is started once and only once
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
}
这里的thread事实上就是NIOServerCnxnFactory
thread = new Thread(this, "NIOServerCxn.Factory:" + addr);
thread.setDaemon(true);
然后来到run()循环
public void run() {
while (!ss.socket().isClosed()) {
try {
selector.select(1000);
Set<SelectionKey> selected;
synchronized (this) {
selected = selector.selectedKeys();
}
ArrayList<SelectionKey> selectedList = new ArrayList<SelectionKey>(
selected);
Collections.shuffle(selectedList);
for (SelectionKey k : selectedList) {
if ((k.readyOps() & SelectionKey.OP_ACCEPT) != 0) {
SocketChannel sc = ((ServerSocketChannel) k
.channel()).accept();
InetAddress ia = sc.socket().getInetAddress();
int cnxncount = getClientCnxnCount(ia);
if (maxClientCnxns > 0 && cnxncount >= maxClientCnxns){
LOG.warn("Too many connections from " + ia
+ " - max is " + maxClientCnxns );
sc.close();
} else {
LOG.info("Accepted socket connection from "
+ sc.socket().getRemoteSocketAddress());
sc.configureBlocking(false);
SelectionKey sk = sc.register(selector,
SelectionKey.OP_READ);
NIOServerCnxn cnxn = createConnection(sc, sk);
sk.attach(cnxn);
addCnxn(cnxn);
}
} else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {
NIOServerCnxn c = (NIOServerCnxn) k.attachment();
c.doIO(k);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Unexpected ops in select "
+ k.readyOps());
}
}
}
selected.clear();
} catch (RuntimeException e) {
LOG.warn("Ignoring unexpected runtime exception", e);
} catch (Exception e) {
LOG.warn("Ignoring exception", e);
}
}
closeAll();
LOG.info("NIOServerCnxn factory exited run method");
}
监听IO,堵塞等待数据到来(1s)
selector.select(1000);
Set<SelectionKey> selected;
synchronized (this) {
selected = selector.selectedKeys();
}
ArrayList<SelectionKey> selectedList = new ArrayList<SelectionKey>(
selected);
Collections.shuffle(selectedList);
假设是连接,则accept。生成则在selector中注冊SelectionKey.OP_READ事件 。在没有达到maxClientCnxns时会创建一个连接createConnection,保存在set中
LOG.info("Accepted socket connection from "
+ sc.socket().getRemoteSocketAddress());
sc.configureBlocking(false);
SelectionKey sk = sc.register(selector,
SelectionKey.OP_READ);
NIOServerCnxn cnxn = createConnection(sc, sk);
sk.attach(cnxn);
addCnxn(cnxn);
处理OP_READ,OP_WRITE 读写时间
if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {
NIOServerCnxn c = (NIOServerCnxn) k.attachment();
c.doIO(k);
}
/**
* Handles read/write IO on connection.
*/
void doIO(SelectionKey k) throws InterruptedException {
try {
if (isSocketOpen() == false) {
LOG.warn("trying to do i/o on a null socket for session:0x"
+ Long.toHexString(sessionId)); return;
}
if (k.isReadable()) {
int rc = sock.read(incomingBuffer);
if (rc < 0) {
throw new EndOfStreamException(
"Unable to read additional data from client sessionid 0x"
+ Long.toHexString(sessionId)
+ ", likely client has closed socket");
}
if (incomingBuffer.remaining() == 0) {
boolean isPayload;
if (incomingBuffer == lenBuffer) { // start of next request
incomingBuffer.flip();
isPayload = readLength(k);
incomingBuffer.clear();
} else {
// continuation
isPayload = true;
}
if (isPayload) { // not the case for 4letterword
readPayload();
}
else {
// four letter words take care
// need not do anything else
return;
}
}
}
if (k.isWritable()) {
// ZooLog.logTraceMessage(LOG,
// ZooLog.CLIENT_DATA_PACKET_TRACE_MASK
// "outgoingBuffers.size() = " +
// outgoingBuffers.size());
if (outgoingBuffers.size() > 0) {
// ZooLog.logTraceMessage(LOG,
// ZooLog.CLIENT_DATA_PACKET_TRACE_MASK,
// "sk " + k + " is valid: " +
// k.isValid()); /*
* This is going to reset the buffer position to 0 and the
* limit to the size of the buffer, so that we can fill it
* with data from the non-direct buffers that we need to
* send.
*/
ByteBuffer directBuffer = factory.directBuffer;
directBuffer.clear(); for (ByteBuffer b : outgoingBuffers) {
if (directBuffer.remaining() < b.remaining()) {
/*
* When we call put later, if the directBuffer is to
* small to hold everything, nothing will be copied,
* so we've got to slice the buffer if it's too big.
*/
b = (ByteBuffer) b.slice().limit(
directBuffer.remaining());
}
/*
* put() is going to modify the positions of both
* buffers, put we don't want to change the position of
* the source buffers (we'll do that after the send, if
* needed), so we save and reset the position after the
* copy
*/
int p = b.position();
directBuffer.put(b);
b.position(p);
if (directBuffer.remaining() == 0) {
break;
}
}
/*
* Do the flip: limit becomes position, position gets set to
* 0. This sets us up for the write.
*/
directBuffer.flip(); int sent = sock.write(directBuffer);
ByteBuffer bb; // Remove the buffers that we have sent
while (outgoingBuffers.size() > 0) {
bb = outgoingBuffers.peek();
if (bb == ServerCnxnFactory.closeConn) {
throw new CloseRequestException("close requested");
}
int left = bb.remaining() - sent;
if (left > 0) {
/*
* We only partially sent this buffer, so we update
* the position and exit the loop.
*/
bb.position(bb.position() + sent);
break;
}
packetSent();
/* We've sent the whole buffer, so drop the buffer */
sent -= bb.remaining();
outgoingBuffers.remove();
}
// ZooLog.logTraceMessage(LOG,
// ZooLog.CLIENT_DATA_PACKET_TRACE_MASK, "after send,
// outgoingBuffers.size() = " + outgoingBuffers.size());
} synchronized(this.factory){
if (outgoingBuffers.size() == 0) {
if (!initialized
&& (sk.interestOps() & SelectionKey.OP_READ) == 0) {
throw new CloseRequestException("responded to info probe");
}
sk.interestOps(sk.interestOps()
& (~SelectionKey.OP_WRITE));
} else {
sk.interestOps(sk.interestOps()
| SelectionKey.OP_WRITE);
}
}
}
} catch (CancelledKeyException e) {
LOG.warn("Exception causing close of session 0x"
+ Long.toHexString(sessionId)
+ " due to " + e);
if (LOG.isDebugEnabled()) {
LOG.debug("CancelledKeyException stack trace", e);
}
close();
} catch (CloseRequestException e) {
// expecting close to log session closure
close();
} catch (EndOfStreamException e) {
LOG.warn("caught end of stream exception",e); // tell user why // expecting close to log session closure
close();
} catch (IOException e) {
LOG.warn("Exception causing close of session 0x"
+ Long.toHexString(sessionId)
+ " due to " + e);
if (LOG.isDebugEnabled()) {
LOG.debug("IOException stack trace", e);
}
close();
}
}
zookeeper启动流程简单梳理的更多相关文章
- Zookeeper启动流程分析
前言 之前的Zookeeper协议篇-Paxos算法与ZAB协议通过了解Paoxs算法开始,到Zab协议的两大特性:崩溃恢复和消息广播,学习了Zookeeper是如何通过Zab协议实现高可用,本篇主要 ...
- 高通msm8994启动流程简单介绍
处理器信息 8994包括例如以下子系统: 子系统 处理器 含义 APSS 4*Cortex-A53 应用子系统 APSS 4*Cortex-A57 应用子系统 LPASS QDSP6 v5.5A(He ...
- zookeeper 3.4.6启动流程粗略梳理
zookeeper 3.4.6 启动脚本里面 nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" " ...
- cinder创建volume的流程-简单梳理
1. cinder-api接收到创建的请求,入口:cinder.api.v2.volumes.VolumeController#create,该方法主要负责一些参数的重新封装和校验,然后调用cinde ...
- busybox启动流程简单解析:从init到shell login
关键词:kernel_init().init.inittab.wait/waitpid.fork/vfork.setsid().execvp/execlp.dup2等等. 由于遇到一系列定制,从ini ...
- Springboot启动流程简单分析
springboot启动的类为SpringApplication,执行构造函数初始化属性值后进入run方法: 然后返回ConfigurableApplicationContext(spring应用). ...
- ORACLE11G R2 RAC的进程启动流程
简要说明ORACLE11GR2 RAC的进程启动流程: 1.启动流程概览图: 二.RAC启动流程的梳理: 第一层:OHASD 启动:(OHASD派生) 1.CSSDAGENT负责启动CSSD的AGEN ...
- netty启动流程
本文通过对netty服务端.客户端的启动流程分析, 让大家对netty是如何启动运行的. 废话不多说,上源码!!! 建议读者学习netty下的jar类型为 netty-example,里面有很多exa ...
- linux启动流程梳理【转】
接触linux系统运维已经好几年了,常常被问到linux系统启动流程问题,刚好今天有空来梳理下这个过程:一般来说,所有的操作系统的启动流程基本就是: 总的来说,linux系统启动流程可以简单总结为以下 ...
随机推荐
- 【转】重装Ubuntu时如何保留/home分区中的数据
Windows系统可以在重装时只格式化C盘,从而保留其他分区的数据. Ubuntu系统也可以,只要在安装系统时分出一个/home分区.你可以把Ubuntu的“/”分区看为Windows的C盘,重装Ub ...
- LeetCode OJ-- Integer to Roman @
@表示有更优解法 https://oj.leetcode.com/problems/integer-to-roman/ 将自然数,转换成罗马数字,输入范围为 1 ~ 3999,因为罗马数没有0. 用一 ...
- git tag 的使用
// 查看tag,列出所有tag,列出的tag是按字母排序的,和创建时间没关系. $ git tag v0.1 v1.3 /查看指定版本的tag,git tag -l “v1.4.2.**” $ gi ...
- C++ STL之count函数
谓词(predicate):是做某些检测的函数,返回用于条件判断的类型,指出条件是否成立. 总结: count : 在序列中统计某个值出现的次数 count_if : 在序列中统计与某谓词匹配的次数 ...
- 洛谷 P1478 陶陶摘苹果(升级版)【贪心/结构体排序/可用01背包待补】
[链接]:https://www.luogu.org/problemnew/show/P1478 题目描述 又是一年秋季时,陶陶家的苹果树结了n个果子.陶陶又跑去摘苹果,这次她有一个a公分的椅子.当他 ...
- AngularJS取得后台Jason数据显示在页面上
代码下载:https://files.cnblogs.com/files/xiandedanteng/angularjsAjax.rar 前台代码: <%@ page language=&quo ...
- iOS 应用内跳转到系统设置
在iOS5下面版本号使用下面方法:[IOS5.1+之后不能使用此方法.iOS8的跳转方法已找到见下方,iOS7的正在摸索,欢迎大家给出观点意见] 通过URL Scheme的方式打开内置的Setting ...
- Putty的噩梦——渗透工具PuttyRider使用心得分享
我们在入侵到一台主机的时候,经常会看到管理员的桌面会放着putty.exe,这说明有很大的可能性管理员是使用putty远程管理主机的. 该工具主要是针对SSH客户端putty的利用,采用DLL注入的方 ...
- 习科小D整理找网站后台办法[科普]
习科科普贴,如何找到网站的后台 作者:小Dの马甲来自:习科论坛 - Silic.Org - BlackBap.Org 1, 穷举猜解 现如今可以暴力猜解网站后台登陆地址的软件有很多,从最早的啊D ...
- 启动Nginx目录浏览功能及 让用户通过用户名密码认证访问web站点
一.启动Nginx目录浏览功能 [root@abcdocker extra]# cat w.conf server { listen 80; server_name IP地址; location / ...