1. 程式人生 > >Zookeeper數據存儲總結

Zookeeper數據存儲總結

eating 事物 process exceptio int c99 from roc 文件

Zookeeper快照文件和事物操作文件以文件的形式存儲在硬盤上,以快照文件為主,日誌文件為輔。因為當對內存數據進行變更的時候,會保證將事務操作記入log日誌,而snapshot只是內存某一個時刻影像,為了性能takeSnapshot生成snapshot並不是實時的,而是由後臺線程根據一定規則處理的。詳細可參考上一篇文章。

快照文件和事物操作文件在磁盤上如下所示:

-rw-rw-r-- 1 ysl ysl  67108880 10月 23 17:43 log.1
-rw-rw-r-- 1 ysl ysl  67108880 11月  7 16:45 log.9b6
-rw-rw-r-- 1 ysl ysl  67108880 1月  15 17:22 log.c99a
-rw-rw-r-- 1 ysl ysl  67108880 1月  16 09:10 log.ca33
-rw-rw-r-- 1 ysl ysl  67108880 1月  17 11:09 log.ca45
-rw-rw-r-- 1 ysl ysl  67108880 1月  18 12:00 log.ca4c
-rw-rw-r-- 1 ysl ysl  67108880 1月  24 17:59 log.ca52
-rw-rw-r-- 1 ysl ysl  67108880 11月  8 16:34 log.ca8
-rw-rw-r-- 1 ysl ysl  67108880 11月  9 17:32 log.d16
-rw-rw-r-- 1 ysl ysl  67108880 1月  30 15:44 log.d172
-rw-rw-r-- 1 ysl ysl  67108880 2月   1 11:52 log.d18d
-rw-rw-r-- 1 ysl ysl  67108880 2月   2 10:10 log.d1aa
-rw-rw-r-- 1 ysl ysl  67108880 11月 10 16:20 log.d88
-rw-rw-r-- 1 ysl ysl       296 10月 23 12:20 snapshot.0
-rw-rw-r-- 1 ysl ysl      6746 11月 13 09:14 snapshot.104d
-rw-rw-r-- 1 ysl ysl      6746 11月 14 11:00 snapshot.1461
-rw-rw-r-- 1 ysl ysl      5059 10月 24 12:11 snapshot.14f
-rw-rw-r-- 1 ysl ysl      5349 10月 25 10:04 snapshot.20a
-rw-rw-r-- 1 ysl ysl      5277 10月 25 10:21 snapshot.210
-rw-rw-r-- 1 ysl ysl      5277 10月 27 14:10 snapshot.21c
-rw-rw-r-- 1 ysl ysl      5349 10月 30 09:17 snapshot.30d
-rw-rw-r-- 1 ysl ysl      5277 10月 30 11:21 snapshot.313

以上文件名是以log.或者snapshot.加上一串long的16進制數字組成,這個long值就是zxid服務器端事務id。Snapshot文件名生成邏輯在 FileTxnSnapLog.save方法中,如下:

    public void save(DataTree dataTree,
            ConcurrentHashMap<Long, Integer> sessionsWithTimeouts)
        throws IOException {
        long lastZxid = dataTree.lastProcessedZxid;
        File snapshotFile = new File(snapDir, Util.makeSnapshotName(lastZxid));
    ........
    }

Util.makeSnapshotName用於生成文件名稱

    public static String makeSnapshotName(long zxid) {
    //返回文件名稱
        return "snapshot." + Long.toHexString(zxid);
    }

日誌Log文件生成,在FileTxnLog.apend方法中,如果被執行了rollLog方法,那麽文件輸入流會被清空,這裏會創建一個新的文件

if (logStream==null) {
       if(LOG.isInfoEnabled()){
            LOG.info("Creating new log file: log." +  
                    Long.toHexString(hdr.getZxid()));
       }
       
       logFileWrite = new File(logDir, ("log." + 
               Long.toHexString(hdr.getZxid())));
       fos = new FileOutputStream(logFileWrite);
       logStream=new BufferedOutputStream(fos);
       .........
    }

當客戶端請求一個事物操作時,leader的PrepRequestProcessor處理器會對請求進行預處理包括生成zxid設置到請求中去,zxid的生成是通過調用ZookeeperServer.getNextZxid生成:

    long getNextZxid() {
        return hzxid.incrementAndGet();
    }

它是hzxid一個自增的long值,有沒有奇怪這個變量取名叫做hzixd多了一個h, h我的理解是high的縮寫代表64位long的高32位。Zxid的分為兩部分高32位用來存儲每次選舉的時代epoch,低32位用來存儲事務請求的自增序列。所謂選舉時代就是一個數值,標記代表一次選舉,跟年份一樣是自增的。每次服務器啟動或者zookeeper異常導致重新選舉都會在原來epoch值加一代表一個新的時代,工具類ZxidUtils用來操作前32或者後32位。比如現在epoch=4代表經歷了4次選舉,如果重新選舉後epoch值為5,通過工具類的zxid=hzxid=ZxidUtils.makeZxid(5,0)= 21474836480,此時低32重新開始值為0, 如果這時來了新的請求值為zxid=21474836481=21474836480+ 1 = ZxidUtils.makeZxid(5, 1)。

public class ZxidUtils {
    static public long getEpochFromZxid(long zxid) {
        return zxid >> 32L;
    }
    static public long getCounterFromZxid(long zxid) {
        return zxid & 0xffffffffL;
    }
    static public long makeZxid(long epoch, long counter) {
        return (epoch << 32L) | (counter & 0xffffffffL);
    }
    static public String zxidToString(long zxid) {
        return Long.toHexString(zxid);
    }
}

Zookeeper數據存儲總結