10、Zookeeper的数据与存储

一、内存数据

Zookeeper的数据模型是树结构,在内存数据库中,存储了整棵树的内容,包括所有的节点路径、节点数据、ACL信息,Zookeeper会定时将这个数据存储到磁盘上。

1、DataTree

DataTree是内存数据存储的核心,是一个树结构,代表了内存中一份完整的数据。DataTree不包含任何与网络、客户端连接及请求处理相关的业务逻辑,是一个独立的组件。

2、DataNode

DataNode是数据存储的最小单元,其内部除了保存了结点的数据内容、ACL列表、节点状态之外,还记录了父节点的引用和子节点列表两个属性,其也提供了对子节点列表进行操作的接口。

3、ZKDatabase

Zookeeper的内存数据库,管理Zookeeper的所有会话、DataTree存储和事务日志。ZKDatabase会定时向磁盘dump快照数据,同时在Zookeeper启动时,会通过磁盘的事务日志和快照文件恢复成一个完整的内存数据库。

二、事务日志

1、文件存储

在配置Zookeeper集群时需要配置dataDir目录,其用来存储事务日志文件。也可以为事务日志单独分配一个文件存储目录:dataLogDir。若配置dataLogDir为/home/admin/zkData/zk_log,那么Zookeeper在运行过程中会在该目录下建立一个名字为version-2的子目录,该目录确定了当前Zookeeper使用的事务日志格式版本号,当下次某个Zookeeper版本对事务日志格式进行变更时,此目录也会变更,即在version-2子目录下会生成一系列文件大小一致(64MB)的文件。

2、日志格式

在配置好日志文件目录,启动Zookeeper后,完成如下操作

(1) 创建/test_log节点,初始值为v1。
(2) 更新/test_log节点的数据为v2。
(3) 创建/test_log/c节点,初始值为v1。
(4) 删除/test_log/c节点。

经过四步操作后,会在/log/version-2/目录下生成一个日志文件,笔者下是log.cec。

将Zookeeper下的zookeeper-3.4.6.jar和slf4j-api-1.6.1.jar复制到/log/version-2目录下,使用如下命令打开log.cec文件。

java -classpath ./zookeeper-3.4.6.jar:./slf4j-api-1.6.1.jar org.apache.zookeeper.server.LogFormatter log.cec

《10、Zookeeper的数据与存储》

(1) ZooKeeper Transactional Log File with dbid 0 txnlog format version 2 :是文件头信息,主要是事务日志的DBID和日志格式版本。

(2) …session 0x159…0xcec createSession 30000:表示客户端会话创建操作。

(3) …session 0x159…0xced create ‘/test_log,… :表示创建/test_log节点,数据内容为#7631(v1)。

(4) …session 0x159…0xcee setData ‘/test_log,…:表示设置了/test_log节点数据,内容为#7632(v2)。

(5) …session 0x159…0xcef create ’/test_log/c,…:表示创建节点/test_log/c。

(6) …session 0x159…0xcf0 delete ‘/test_log/c:表示删除节点/test_log/c。

3、日志写入

FileTxnLog负责维护事务日志对外的接口,包括事务日志的写入和读取等。Zookeeper的事务日志写入过程大体可以分为如下6个步骤。

(1) 确定是否有事务日志可写:当Zookeeper服务器启动完成需要进行第一次事务日志的写入,或是上一次事务日志写满时,都会处于与事务日志文件断开的状态,即Zookeeper服务器没有和任意一个日志文件相关联。因此在进行事务日志写入前,Zookeeper首先会判断FileTxnLog组件是否已经关联上一个可写的事务日志文件。若没有,则会使用该事务操作关联的ZXID作为后缀创建一个事务日志文件,同时构建事务日志的文件头信息,并立即写入这个事务日志文件中去,同时将该文件的文件流放入streamToFlush集合,该集合用来记录当前需要强制进行数据落盘的文件流。

(2) 确定事务日志文件是否需要扩容(预分配):Zookeeper会采用磁盘空间预分配策略。当检测到当前事务日志文件剩余空间不足4096字节时,就会开始进行文件空间扩容,即在现有文件大小上,将文件增加65536KB(64MB),然后使用”0″填充被扩容的文件空间。

(3) 事务序列化:对事务头和事务体的序列化,其中事务体又可分为会话创建事务、节点创建事务、节点删除事务、节点数据更新事务等。

(4) 生成Checksum:为保证日志文件的完整性和数据的准确性,Zookeeper在将事务日志写入文件前,会计算生成Checksum。

(5) 写入事务日志文件流:将序列化后的事务头、事务体和Checksum写入文件流中,此时并为写入到磁盘上。

(6) 事务日志刷入磁盘:由于步骤5中的缓存原因,无法实时地写入磁盘文件中,因此需要将缓存数据强制刷入磁盘。

4、日志截断

在Zookeeper运行过程中,可能出现非Leader记录的事务ID比Leader上大,这是非法运行状态。此时,需要保证所有机器必须与该Leader的数据保持同步,即Leader会发送TRUNC命令给该机器,要求进行日志截断,Learner收到该命令后,就会删除所有包含或大于该事务ID的事务日志文件。

三、snapshot-数据快照

数据快照是Zookeeper数据存储中非常核心的运行机制,数据快照用来记录Zookeeper服务器上某一时刻的全量内存数据内容,并将其写入指定的磁盘文件中。

1、 文件存储

与事务文件类似,Zookeeper快照文件也可以指定特定磁盘目录,通过dataDir属性来配置。若指定dataDir为/home/admin/zkData/zk_data,则在运行过程中会在该目录下创建version-2的目录,该目录确定了当前Zookeeper使用的快照数据格式版本号。在Zookeeper运行时,会生成一系列文件。

2、数据快照

FileSnap负责维护快照数据对外的接口,包括快照数据的写入和读取等,将内存数据库写入快照数据文件其实是一个序列化过程。针对客户端的每一次事务操作,Zookeeper都会将他们记录到事务日志中,同时也会将数据变更应用到内存数据库中,Zookeeper在进行若干次事务日志记录后,将内存数据库的全量数据Dump到本地文件中,这就是数据快照。其步骤如下

(1) 确定是否需要进行数据快照:每进行一次事务日志记录之后,Zookeeper都会检测当前是否需要进行数据快照,考虑到数据快照对于Zookeeper机器的影响,需要尽量避免Zookeeper集群中的所有机器在同一时刻进行数据快照。采用过半随机策略进行数据快照操作。

(2) 切换事务日志文件:表示当前的事务日志已经写满,需要重新创建一个新的事务日志。

(3) 创建数据快照异步线程:创建单独的异步线程来进行数据快照以避免影响Zookeeper主流程。

(4) 获取全量数据和会话信息:从ZKDatabase中获取到DataTree和会话信息。

(5) 生成快照数据文件名:Zookeeper根据当前已经提交的最大ZXID来生成数据快照文件名。

(6) 数据序列化:首先序列化文件头信息,然后再对会话信息和DataTree分别进行序列化,同时生成一个Checksum,一并写入快照数据文件中去。

参考:http://blog.csdn.net/zdy0_2004/article/details/53711170

    原文作者:yannhuang
    原文地址: https://www.jianshu.com/p/8fba732af0cd
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞