Zookeeper是能够存储数据的,因此咱们能够把它理解一个数据库,实际上它的底层原理自己也和数据库是相似的。node
咱们知道,数据库是用来存储数据的,只是数据能够存储在内存中或磁盘中。而Zookeeper实际是结合了这两种的,Zookeeper中的数据即会存储在磁盘中以达到持久化的目的,也会同步到内存中以到达快速访问的目的。sql
事实上,用过Zookeeper的同窗应该知道,Zookeeper中有两种类型的节点:持久化节点和临时节点。数据库
做为一个数据库,确定是要接收客户端建立、修改、删除、查询节点等请求的。服务器
在Zookeeper中对于请求分为两类:微信
Zookeeper一般都是以集群模式运行的,也就是Zookeeper集群中各个节点的数据须要保持一致的。可是和Mysql集群不同的是:异步
Zookeeper集群底层是怎么保证数据一致性的,实际上是用的两阶段提交+过半机制来保证的,后面会单独写一篇文章来介绍这个的底层实现,感兴趣的能够关注一下个人微信公众号:1点25学习
事务性请求包括:更新操做、新增操做、删除操做,结合上面的分析,由于这些操做是会影响数据的,因此要保证这些操做在整个集群内的事务性,因此这些操做就是事务性请求。日志
那么非事务性请求就好理解的,像查询操做、exist操做这些不影响数据的操场,就不须要集群来保持事务性,因此这些操场就是非事务性请求。code
Zookeeper在处理事务性请求时,比处理非事务性请求要复杂不少cdn
假设咱们如今在Zookeeper中有一个数据节点,节点名为/datanode
,内容为125
,该节点是持久化节点,因此该节点信息会保存在文件中。
可能你们都会认为是相似下面这样方式保存在磁盘文件中的,方法一:
节点名 | 节点内容 |
---|---|
/datanode | 125 |
可是除开这种表示方法,还有另一种表示方法,快照+事务日志,好比方法二:
当前快照:
节点名 | 节点内容 |
---|---|
/datanode | 120 |
当前事务日志:
事务ID | 操做 | 节点名 | 节点内容修改前 | 节点内容修改后 |
---|---|---|---|---|
1000010 | update | /datanode | 120 | 121 |
1000011 | update | /datanode | 121 | 125 |
乍一看方法二比方法一要更复杂,而且占用的磁盘更多。可是咱们上文提到过,Zookeeper集群中的节点在处理事务性请求时,须要将事务操做同步给其余节点,因此这里的事务操做是必定要进行持久化的,以便在同步给其余节点时出现异常进行补偿。因此就出现了事务日志。实际上事务日志还运行数据进行回滚,这个在两阶段提交中也是很是重要的。
那么快照又有什么用呢?事务日志必定要有,可是随着时间的推移,日志确定会愈来愈多,因此确定不能持久化历史上全部的日志,因此Zookeeper会定时的进行快照,并删除以前的日志。
那么若是按方法二这么存储数据,在对数据进行查询时就不太方便了。上文说到,Zookeeper为了提升数据的查询速度,会在内存中也存储一份数据,那么内存中的这份数据又该怎么存呢?
Zookeeper中的数据在内存中的表示其实和上文的方法一很相似,只是Zookeeper中的数据是具备文件目录特色的,说白了就是Zookeeper中的数据节点的名字必定要以“/”
开头,这样就致使Zookeeper中的数据相似一颗树:
一颗具备父子层级的多叉树,在Zookeeper源码中叫DataTree。
请看下图:
请注意,对于上图,Zookeeper真正的底层实现,zk1是Leader,zk2和zk3是Learner,是根据领导者选举选出来的。
非事务性请求直接读取DataTree上的内容,DataTree是在内存中的,因此会很是快。
这篇文章介绍了Zookeeper在处理请求时的几个核心概念:
下篇文章来详细的介绍一下Zookeeper处理请求时二阶段提交是如何实现的。
有痛点才有创新,一个技术确定都是为了解决某个痛点才出现的。 请帮忙转发一下,若是想第一时间学习更多的精彩的内容,请关注微信公众号:1点25