1. 程式人生 > >Zookeeper詳解(八):Zookeeper數據存儲

Zookeeper詳解(八):Zookeeper數據存儲

標準 一份 數據結構 創建 指定 樹形數據 mic 正在 所有

zookeeper日誌有三類:快照(雖然不是日誌但是它是數據)、事務日誌(記錄每次操作)、zookeeper自己系統日誌。第三個不屬於數據類所以這裏不做說明。


快照數據

Zookeeper在運行時會在內存中維護一個完整的數據,就像內存數據庫一樣。ZKDatabase就是Zookeeper的內存數據庫,負載管理Zookeeper的會話、存儲和事務日誌。它會定期dump一份數據快照到硬盤上,在Zookeeper啟動時根據這個快照數據和事務日誌來加載一份完整的數據到內存。這一點跟Redis很像,其實很多時候思路都是一樣。

通過在配置文件中設置dataDir來指定快照保存位置。將內存數據庫寫入快照文件其實是一個序列化的過程。快照文件保存只是每個節點的元數據而非數據本身

那麽每次快照間隔多久呢?

其實可以通過snapCount來進行配置,這個值得含義是每次快照之間的事務數量。也就是說執行多少次事務操作後進行一次快照。


  1. 每完成一次事務操作Zookeeper都會檢查是否達到snapCount設置也就是來判斷是否需要進行快照操作,因為快照本身對機器性能有影響,要避免集群中所有節點都進行快照

  2. 如果要進行快照操作,首先就需要對事務日誌進行截斷然後切換,所以事務日誌寫滿不是以64M為標準而是以事務條數為標準的。

  3. 創建異步線程來執行快照操作(這一點又和Redis的bgsave一樣)

  4. 從ZKDatabase中獲取全量數據和會話,因為要保存內存所有數據節點信息和會話信息

  5. 生成快照名稱,會根據已提交的最大ZXID來生成快照名稱

  6. 數據序列化,首先會序列化文件頭信息(魔數、版本、dbid信息),然後對會話信息和DataTree(Zookeeper內存數據的核心一個樹形數據結構,代表內存完整數據)分別序列化,同時生成一個校驗和,然後一起寫入數據文件中。


事務日誌

在配置文件中通過dataLogDir來配置事務日誌路徑,如果不配置默認保存在dataDir指定的路徑下面。

技術分享圖片

這些文件都是65M,其實是64M。而且都是以log.開頭後面是一個十六進制數字作為後綴。這個後綴是一個ZXID它是寫入該日誌的第一個事務的事務ID,這樣可以達到快速定位某一事務的效果。


日誌寫入過程:

  1. 當需要寫入事務日誌的時候Zookeeper會判斷它是否和一個可寫入的事務日誌相關聯,如果關聯就寫入,如果沒有則用該事務的事務ID來創建一個事務日誌,同時將這個事務日誌對應的文件流放入到一個集合中(streamsToFlush),這個集合中記錄的是當前需要強刷數據到磁盤的文件流(因為操作系統通常有延遲寫入機制,對於Linux系統強刷等於調用fsync)。

  2. 事務日誌文件采用預先分配空間策略,這樣為了保證單一事務日誌文件所占用的磁盤塊是連續的,這也是為了提高性能。當Zookeeper發現當前正在寫入的事務日誌文件空間不足4KB時,就會啟動預先分配空間策略進行擴容。第一次使用事務日誌或者事務日誌達到切割條數(snapCount參數觸發快照)會啟動預先分配策略;其他時候只要發現當前使用的事務日誌空余不足4KB就進行擴容,擴容時使用0進行填充。

  3. 確保日誌文件空間夠之後就需要對進行事務序列化操作,最終產生一個字節數組。主要對事務頭(TxnHeader)和事務體(Record)進行序列化。

  4. 根據序列化後的字節數據計算一個校驗和

  5. 將字節數組和校驗寫入到文件流中。

  6. 由於該事務日誌的文件流在集合中,這時候就會從集合裏面取出文件流強刷落盤。

Zookeeper詳解(八):Zookeeper數據存儲