Zookeeper数据内存模型和磁盘存储

一、内存结构

        类似Unix的文件系统,Zookeeper在内存中维护着一个树形层级结构,只不过没有目录,每个节点被成为znode.znode可以存放数据,并有自己的访问权限列表和关联的统计信息(stat). 

        然而Zookeeper是用来设计作为协同服务的,而不是用于大容量数据存储。虽然每个znode上的数据上限是1M.即便如此,我们还是不推荐开发人员按照这个上限来使用,因为客户端的写请求在服务端都是串行处理,数据的传输会大大影响性能。

        在内存中,DataTree维护着ZNode的树形结构,然而在处理来自于客户端的对目标节点的操作请求时,zk并非从根节点层层找到目标节点,而是通过另外一个hashtable通过全路径直接定位到目标节点。这样做的目的是为了提高查找效率,将复杂度从O(pathNodes)降低到O(1).

1
private  final  ConcurrentHashMap<String, DataNode> nodes =  new ConcurrentHashMap<String, DataNode>();


    在DataNode上除了其parent,data,acl,children等属性外,还保存了一些统计数据Stat:

1
2
3
4
5
6
7
8
9
czxid   创建这个znode的zxid
mzxid   最后一次修改这个znode的zxid
ctime   该znode创建时间
mtime   该znode最后一次修改的时间
version     该znode的version,也就是该znode的修改次数。
cversion    该znode的子节点的更新次数
aversion    该znode的ACL信息更新次数
ephemeralOwner  如果该znode是ephemeral node,此字段就是对应client的sessionId;否则为0。
pzxid       create or delete childnode txn id


二、磁盘存储

        ZK的数据存储在磁盘上分为快照和事务日志两种:


        1.对于客户端的写请求zk会将其写入到transaction log中

        2.如果事务日志达到一定数量,则产生一个新日志,并启动一个线程进行进行takeSnapshot,把当前的内存DataTree和会话信息写入到snapshot file中,snapshot的文件名以datatree的最后处理的transactionId为结尾

        3.ZK在启动的时候首先将snapshot从磁盘加载到内存的DataTree中,然后根据dataTree.lastProcessedZxid+1找到需要处理的transaction log记录,一一附加到datatree上。


        Zookeeper高效原因之一就是对请求的处理主要是操作内存结构. 然而对于每个写请求都需要写事务日志,为了提高append日志效率,zk使用了group commit机制,也就是并非每条日志都直接flush到磁盘上,而是等到多个请求产生的日志缓存起来,到达指定条数后,一次性flush到磁盘上。

        此外zk为了在运行过程中迅速地向事务日志文件中append记录,为每个txn log文件预先分配了指定大小的磁盘块(通过preAllocSize来设置),默认是64M,接近这个值的时候(少于4k)便会再次分配64M.这样做的原因是如果没有预先分配,那么写完一个块的话就要重新分配,会带来额外的磁盘寻道。


        preAllocSize默认是64M,但是我们可以根据snapCount(事务日志达到多少条便产生一个snapshot)的数量来预估事务日志文件的大小。这是因为每当达到snapCount对应的事务日志条数后,便会产生一个新日志(rollLog)。合理的预估有助于避免空间浪费。


        我们看一下快照文件的二进制结构:  snapshotStructure.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
由于图较小,无法将具体信息都放进去,我们看下ACL和DataNode的具体结构:
Map<nodeAcl,List<ACL>>
nodeAcl(long)
 
ACL:
scheme(string)
identifier(string)
permissions(int)
 
 
Tree<DataNode> 从根节点开始开始遍历
 
path(string)
data(bytes)
acl(long) access control list
czxid(long) createNode txn id
mzxid(long) setData txn id
ctime(long) createNode time
mtime(long) setData time
version(int) increase when setData
cversion(int) increase when delete or create childnode
aversion(int) setAcl txn id
ephemeralOwner(long) It is sessionId if ephemeral node,else 0
pzxid(long) create or delete childnode txn id

        我们再看一下事务日志文件的二进制结构:transactionlogStructure.jpg




http://www.mthinking.net/blog/tecnology/dailylearning/918bc3a1-e154-4175-82b5-cd539c67c55f




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值