ZookeeperServer詳解

首先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

接下來轉戰hadoop ^v^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章