【Zookeeper】原始碼分析之伺服器(四)之FollowerZooKeeperServer

leesf發表於2017-03-08

一、前言

  前面分析了LeaderZooKeeperServer,接著分析FollowerZooKeeperServer。

二、FollowerZooKeeperServer原始碼分析

  2.1 類的繼承關係  

public class FollowerZooKeeperServer extends LearnerZooKeeperServer {}

  說明:其繼承LearnerZooKeeperServer抽象類,角色為Follower。其請求處理鏈為FollowerRequestProcessor -> CommitProcessor -> FinalRequestProcessor。

  2.2 類的屬性  

public class FollowerZooKeeperServer extends LearnerZooKeeperServer {
    private static final Logger LOG =
        LoggerFactory.getLogger(FollowerZooKeeperServer.class);
    // 提交請求處理器
    CommitProcessor commitProcessor;
    
    // 同步請求處理器
    SyncRequestProcessor syncProcessor;

    /*
     * Pending sync requests
     */
    // 待同步請求
    ConcurrentLinkedQueue<Request> pendingSyncs;
    
    // 待處理的事務請求
    LinkedBlockingQueue<Request> pendingTxns = new LinkedBlockingQueue<Request>();
}

  說明:FollowerZooKeeperServer中維護著提交請求處理器和同步請求處理器,並且維護了所有待同步請求佇列和待處理的事務請求佇列。

  2.3 類的建構函式  

    FollowerZooKeeperServer(FileTxnSnapLog logFactory,QuorumPeer self,
            DataTreeBuilder treeBuilder, ZKDatabase zkDb) throws IOException {
        super(logFactory, self.tickTime, self.minSessionTimeout,
                self.maxSessionTimeout, treeBuilder, zkDb, self);
        // 初始化pendingSyncs
        this.pendingSyncs = new ConcurrentLinkedQueue<Request>();
    }

  說明:其首先呼叫父類的建構函式,然後初始化pendingSyncs為空佇列。

  2.4 核心函式分析

  1. logRequest函式  

    public void logRequest(TxnHeader hdr, Record txn) {
        // 建立請求
        Request request = new Request(null, hdr.getClientId(), hdr.getCxid(),
                hdr.getType(), null, null);
        // 賦值請求頭、事務體、zxid
        request.hdr = hdr;
        request.txn = txn;
        request.zxid = hdr.getZxid();
        if ((request.zxid & 0xffffffffL) != 0) { // zxid不為0,表示本伺服器已經處理過請求
            // 則需要將該請求放入pendingTxns中
            pendingTxns.add(request);
        }
        // 使用SyncRequestProcessor處理請求(其會將請求放在佇列中,非同步進行處理)
        syncProcessor.processRequest(request);
    }

  說明:該函式將請求進行記錄(放入到對應的佇列中),等待處理。

  2. commit函式 

    public void commit(long zxid) {
        if (pendingTxns.size() == 0) { // 沒有還在等待處理的事務
            LOG.warn("Committing " + Long.toHexString(zxid)
                    + " without seeing txn");
            return;
        }
        // 隊首元素的zxid
        long firstElementZxid = pendingTxns.element().zxid;
        if (firstElementZxid != zxid) { // 如果隊首元素的zxid不等於需要提交的zxid,則退出程式
            LOG.error("Committing zxid 0x" + Long.toHexString(zxid)
                    + " but next pending txn 0x"
                    + Long.toHexString(firstElementZxid));
            System.exit(12);
        }
        // 從待處理事務請求佇列中移除隊首請求
        Request request = pendingTxns.remove();
        // 提交該請求
        commitProcessor.commit(request);
    }

  說明:該函式會提交zxid對應的請求(pendingTxns的隊首元素),其首先會判斷隊首請求對應的zxid是否為傳入的zxid,然後再進行移除和提交(放在committedRequests佇列中)。

  3. sync函式  

    synchronized public void sync(){
        if(pendingSyncs.size() ==0){ // 沒有需要同步的請求
            LOG.warn("Not expecting a sync.");
            return;
        }
        // 從待同步佇列中移除隊首請求
        Request r = pendingSyncs.remove();
        // 提交該請求
        commitProcessor.commit(r);
    }

  說明:該函式會將待同步請求佇列中的元素進行提交,也是將該請求放入committedRequests佇列中。

三、總結

  本篇學習了FollowerZooKeeperServer的原始碼,其核心是對待同步請求和待處理事務請求交由不同的請求處理器進行處理。也謝謝各位園友的觀看~

相關文章