首先zookeeper server的位置在代碼中org/apache/zookeeper/server這個package下面。之前有說過,zookeeper的啓動類是ZookeeperServerMain.java這個類,在這個類中使用了
final ZooKeeperServer zkServer = new ZooKeeperServer(txnLog, config.tickTime, config.minSessionTimeout, config.maxSessionTimeout, null);
對ZookeeperServer進行實例化,其中txnLog是數據存儲封裝類,日誌也是一種數據存儲咯。然後在有
cnxnFactory = ServerCnxnFactory.createFactory();
//上面的具體點就是
ServerCnxnFactory serverCnxnFactory = (ServerCnxnFactory) Class.forName(serverCnxnFactoryName).getDeclaredConstructor().newInstance();
// 具體點就是NIOServerCnxnFactory
//在這個類中
cnxnFactory.startup(zkServer);
//具體的操作就是
start();
setZooKeeperServer(zks);
if (startServer) {
zks.startdata();
zks.startup();
}
其中zks.startup()具體操作就是
//這個從名字上應該可以猜到是幹啥的,session跟蹤器,管理session的
if (sessionTracker == null) {
createSessionTracker();
}
startSessionTracker();
//這個就很重要了
setupRequestProcessors();
//jmx的管理
registerJMX();
//設置狀態
setState(State.RUNNING);
notifyAll();
其中setupRequestProcessors()的具體內容爲
RequestProcessor finalProcessor = new FinalRequestProcessor(this);
RequestProcessor syncProcessor = new SyncRequestProcessor(this, finalProcessor);
((SyncRequestProcessor)syncProcessor).start();
firstProcessor = new PrepRequestProcessor(this, syncProcessor);
((PrepRequestProcessor)firstProcessor).start();
很明顯是一種責任鏈的操作模式。具體每種processor是做什麼的請看代碼。在PrepRequestProcessor中,有LinkedBlockingQueue submittedRequests = new LinkedBlockingQueue();可以看到,其實處理器共享了請求隊列,每次取出一個請求對其依次處理。那麼這個submittedRequests從哪裏來的呢? 繼續看代碼。首先,在下面的函數(同樣在PrepRequestProcessor類中)中,有下面代碼
public void processRequest(Request request) {
submittedRequests.add(request);
}
在ZooKeeperServer類中,有
public void submitRequest(Request si) {
if (firstProcessor == null) {
synchronized (this) {
try {
// Since all requests are passed to the request
// processor it should wait for setting up the request
// processor chain. The state will be updated to RUNNING
// after the setup.
while (state == State.INITIAL) {
wait(1000);
}
} catch (InterruptedException e) {
LOG.warn("Unexpected interruption", e);
}
if (firstProcessor == null || state != State.RUNNING) {
throw new RuntimeException("Not started");
}
}
}
try {
touch(si.cnxn);
boolean validpacket = Request.isValid(si.type);
if (validpacket) {
firstProcessor.processRequest(si);
if (si.cnxn != null) {
incInProcess();
}
} else {
LOG.warn("Received packet at server of unknown type " + si.type);
new UnimplementedRequestProcessor().processRequest(si);
}
} catch (MissingSessionException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Dropping request: " + e.getMessage());
}
} catch (RequestProcessorException e) {
LOG.error("Unable to process request:" + e.getMessage(), e);
}
}
同樣在ZookeeperServer類中的
public void processPacket(ServerCnxn cnxn, ByteBuffer incomingBuffer) throws IOException {}
long createSession(ServerCnxn cnxn, byte passwd[], int timeout) {}
private void close(long sessionId) {}
函數中,存在着submitRequest(si);命令。
我們以processPacket爲例,繼續跟進。
在NIOServerCnxn中,
private void readRequest() throws IOException {
zkServer.processPacket(this, incomingBuffer);
}
一直找下去可以找到
workerPool = new WorkerService(“NIOWorker”, numWorkerThreads, false);這個類在NIOServerCnxnFactory的內部私有類AcceptThread中被實例化,伴隨着一起實例化的是
for(SelectorThread thread : selectorThreads) {
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
}
// ensure thread is started once and only once
if (acceptThread.getState() == Thread.State.NEW) {
acceptThread.start();
}
if (expirerThread.getState() == Thread.State.NEW) {
expirerThread.start();
}
再粘帖下AcceptThread的描述,該類之前的博文裏面有介紹一些內容。
/**
* There is a single AcceptThread which accepts new connections and assigns
* them to a SelectorThread using a simple round-robin scheme to spread
* them across the SelectorThreads. It enforces maximum number of
* connections per IP and attempts to cope with running out of file
* descriptors by briefly sleeping before retrying.
*/
以上是ZookeeperServer作爲一個服務的核心處理環節。ZookeeperServer一共有以下的內部變量
protected static final Logger LOG;
static {
LOG = LoggerFactory.getLogger(ZooKeeperServer.class);
Environment.logEnv("Server environment:", LOG);
}
protected ZooKeeperServerBean jmxServerBean;
protected DataTreeBean jmxDataTreeBean;
public static final int DEFAULT_TICK_TIME = 3000;
protected int tickTime = DEFAULT_TICK_TIME;
/** value of -1 indicates unset, use default */
protected int minSessionTimeout = -1;
/** value of -1 indicates unset, use default */
protected int maxSessionTimeout = -1;
protected SessionTracker sessionTracker;
private FileTxnSnapLog txnLogFactory = null;
private ZKDatabase zkDb;
private final AtomicLong hzxid = new AtomicLong(0);
public final static Exception ok = new Exception("No prob");
protected RequestProcessor firstProcessor;
protected volatile State state = State.INITIAL;
protected enum State {
INITIAL, RUNNING, SHUTDOWN, ERROR
}
/**
* This is the secret that we use to generate passwords, for the moment it
* is more of a sanity check.
*/
static final private long superSecret = 0XB3415C00L;
private final AtomicInteger requestsInProcess = new AtomicInteger(0);
final List<ChangeRecord> outstandingChanges = new ArrayList<ChangeRecord>();
// this data structure must be accessed under the outstandingChanges lock
final Map<String, ChangeRecord> outstandingChangesForPath =
new HashMap<String, ChangeRecord>();
protected ServerCnxnFactory serverCnxnFactory;
protected ServerCnxnFactory secureServerCnxnFactory;
private final ServerStats serverStats;
private final ZooKeeperServerListener listener;
private ZooKeeperServerShutdownHandler zkShutdownHandler;
首先是管理擴展的幾個Bean,接着是服務的參數
txnLogFactory是用來讀寫日誌的
zkDb則管理着zookeeper的文件樹結構
firstProcessor是處理器的入口
state標誌着服務狀態,用volatile保證了它的可見性
serverCnxnFactory和secureServerCnxnFactory是管理服務連接與處理流程的工廠,說工廠也不太合適,ServerCnxnFactory主要工作還是服務的管理和連接的控制,基本上核心流程都會與這個有關。
serverStats管理着服務的當前各類數據
zkShutdownHandler是處理服務關閉的鉤子
ZookeeperServer相當於一個管理的大手,指揮着服務所有過程。核心代碼。
zookeeper代碼看了有一段時間了,用自己的話來說,zookeeper是一個分佈式的存儲服務組件,該組件具有較高的一致性和安全性,可以用作各種配置管理類的服務。其代碼由幾大重要部分組成,一是連接管理和控制,二是小數據存儲服務,三是不同機器服務協調機制,四是jmx管理擴展模塊。
這裏也推薦其它的一些zookeeper博文,可以做一個對照來看,即使本系列文章有錯誤,不夠精彩或者沒講到的地方,也可以通過下面的文章進行完善。
1.http://shift-alt-ctrl.iteye.com/blog/1845568
2.https://www.cnblogs.com/gpcuster/archive/2010/12/29/1921213.html
3.http://cailin.iteye.com/blog/2014486/
4.http://blog.csdn.net/dengsilinming/article/details/18224925