Zookeeper数据的组织形式为一个类似的文件系统的数据结构,而这些数据都是存储在内存中的,
所以我们可以认为,Zookeeper是一个基于内存的小型数据库
内存中的数据
public class DataTree {
private final ConcurrentHashMap<String,DataNode> nodes = new ConcurrentHashMap<String,DataNode>();
private final WatchManager dataWatches = new WatchManager();
private final WatchManager childWatches = new WatchManager();
}
DataNode 是Zookeeper存储节点数据的最小节点
public class DataNode implements Record {
byte data[];
Long acl;
public StatPersisted stat;
private Set<String> children = null;
}
事务日志
针对每一次客户端的事务操作,Zookeeper都会将他们记录到事务日志中,当然Zookeeper也会将数据变更到内存数据库中。我们可以在zookeeper的主配置文件zoo.cfg中配置内存中的数据持久化目录,也就是事务日志的存储路径dataLogDir.如果没有配置dataLogDir(非必填),事务日志将存储到dataDir(必填项)目录
zookeeper提供了各式化工具可以进行数据查看事务日志数据
org.apache.zookeeper.server.LogFormatter
java -cp slf4j-log4j12-1.7.25.jar:zookeeper-jute-3.5.9.jar org.apache.zookeeper.server.LogFormatter /app/app/data/log.6e
如下是本地日志格式化的效果
从左到右分别记录了操作时间,客户端会话ID,CXID,ZXID,操作类型,节点路径,节点数据(用#+ascii码表示),节点版本
Zookeeper进行事务日志文件操作的时候会频繁进行磁盘IO操作,事务日志的不断追加操作会触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek。因此,未来提升磁盘IO的效率,Zookeeper在创建事务日志文件的时候就进行文件空间的预分配-即在创建文件的时候,就向操作系统申请一块大一点磁盘块。这个预分配的磁盘大小可以通过系统参数zookeeper.preAllocSize进行配置。
事务日志文件为:log.<当时最大事务ID>,应为日志文件时顺序写入的,所以这个最大事务ID也将是整个事务日志文件中,最小的事务ID,日志满了即进行下一次失误日志文件的创建
数据快照
数据快照用于记录Zookeeper服务器上某一时刻的全量数据,并将其写入到指定磁盘文件中。可以通过配置snapCount配置每间隔失误请求个数,生成快照,数据存储在dataDir指定目录中,可以通过如下方式进行查看快照数据(为了避免集群中所有机器在同一时间进行快照,实际的快照生成时机为事务数到达[snapCount/2 +随机数(随机数(随机数范围为1-snapCount/2)] 个数开始快照)
1 java ‐cp .:slf4j‐api‐1.7.25.jar:zookeeper‐3.5.8.jar:zookeeper‐jute‐ 3.5.8.jar org.apache.zookeeper.server.SnapshotFormatter /data‐dir/version‐2/snapshot.0
创建事务日志文件名为:snapshot<当前最大事务ID>,日志满了即进行下一次事务日志文件的创建
有了事务日志,为啥还要快照数据
快照数据主要是为了快速恢复,事务日志文件是每次事务请求都会进行追加的操作,而快照是达到某种设定条件下的内存全量数据。所以通常快照数据是反应当时内存数据的状态。事务日志更全面的数据,所以恢复数据的时候,可以先恢复快照数据,再通过增量恢复事务日志中的数据即可。