ZooKeeper小结(一)原理解析



zk是一个基础服务,主要功能是提供一个保证分布式部署中数据一致性的框架。基于这个框架可以实现很多功能,比如Hadoop的namenode/datanode结构,hbase的hmaster结构。
1、怎么理解这个框架的含义呢?
分布式:zk可以运行在一个集群中的若干个服务器中(一般是奇数个服务器,便于选举leader)。
数据一致性:zk保证集群中一半以上的服务器保持和leader的数据更新同步,落后的服务器会在客户端操作时强制更新同步。
保证:zk的底层实现可以保证以上两点的实现。
2、zk是怎么实现的呢?
zk在内存中维护一个树状目录,目录从根节点开始,根节点表示为:/。每一个连接到zk并拥有权限的客户端,都可以在树中添加节点、获取树结构或某个节点的子节点树,同时可以在感兴趣的节点上注册观察者(Watch类),当节点发生变化(掉线、数据变更、上线、添加减少子节点等),客户端就会收到相应通知。这就是zk的基本实现。
通过这一过程,zk就可以实现“分布式部署中数据一致性”。举例来说,如Hadoop,在namenode节点服务器中,启动客户端A,连接到zk服务器,添加节点/namenode,指定该节点是leader,并注册/namenode节点的观察者,在该节点数据中保存Hadoop的namenode节点信息(如主机地址)。在datanode节点服务器中,启动客户端B1,连接到zk服务器,添加节点/namenode/datanodeB1,并注册/namenode/datanode1节点的观察者,在该节点中保存Hadoop的datanode节点信息(如父节点地址,本机地址)。类似的可以添加datanode节点B2~Bn。当datanode节点掉线或上线时,zk框架会自动通知所有的观察者,比如namenode,则namenode可以更新自己的datanode节点信息,进行数据添加备份等等Hadoop层的业务逻辑。当namenode掉线时,zk框架会自动启用选举算法,选举出新的namenode(leader),更新目录树,因为zk服务器都是保存的同一个目录树(更新速度有快慢,最终是一致的),所以可以实现namenode的平滑迁移,而Hadoop层可以对namenode的迁移做处理,比如不经过选举,在响应时直接指定从namenode为主namenode,或迁移到选举出的namenode,用元数据启动该namenode。
3、zk的应用
通过上一小节Hadoop应用可以看出,zk提供了一个高度抽象的分布式数据一致性的模型(框架),更重要的是,集群中的任何一个客户端都可以在同一个树状目录的任意节点注册观察者,当节点发生改变时,做出业务逻辑层面的响应。这个框架是非常灵活的,也是非常简单的。框架本身只负责全集群数据一致性(树目录一致性和节点数据一致性),节点消息通知。而上层应用可以基于全局一致性的前提下,对消息通知做出业务逻辑的响应。
回答了“是什么?怎么做?做什么?”的问题,就可以更进一步,了解zk都做了什么。
1、为保证一致性做的工作
1、1 leader
leader的作用,就是让其他所有的从服务器中的数据都和leader同步,即以leader的数据为准。
如果leader就节点掉线,则剩余服务器会发起投票,选举出一个新leader。选举算法叫FastLeaderElection。
为了保证一致性,zk要求所有节点都可以提供读操作,但是只有leader可以进行写操作。leader在进行写操作时,会把要修改的节点和数据发送给所有服务器,只要有半数以上的服务器更新了节点数据,leader就认为数据写成功,并向请求写操作的客户端返回成功;否则认为写操作失败,不对任何节点数据进行修改。所有服务器在写入数据时,都会先把数据写入磁盘实现持久化,然后更新内存中的数据。
zk要求节点数据非常小,一般最多1M,因而可以放在内存中。当客户端从某个服务器请求节点数据时,直接从内存中读取数据,因而zk框架效率非常高。
1、2其他节点follower
因为每次写操作只要半数以上服务器更新了节点数据,即认为数据成功更新,所以其他节点服务器的数据版本有可能落后于leader(但不可能超过leader)。同时,其他节点也负责选举新leader。
当有客户端连接到某个服务器,而该服务器保存的数据(目录树和节点数据)版本落后于leader,则该服务器会拒绝客户端的连接,并向leader请求更新数据。因此在客户端需要有服务器列表(如配置文件),当一个服务器连接失败时,去连接下一个服务器。如果客户端主动调用sync()方法,则会异步让服务器去请求更新数据,而sync()会立即返回,但是zk可以保证在sync()的异步操作完成前,客户端所发出的所有操作不会被执行,当更新完成后,所有提交的操作会被顺序执行。
2、数据原子性
数据的读写具有原子性。读取时,或者一次性读完,或者读取失败时,不返回任何数据。写入时,只有当半数以上的服务器确定写入成功,leader才会返回写入成功,服务器返回成功给连接的客户端,否则写入失败,不写入任何数据。
zk也支持多条数据的同时写入,即mulit操作。如果一组数据中的某一条写入失败,则整组失败,不会把其他已写入成功的数据保留。
3、更新持久化
所有的更新都会被持久化记录,而且因为更新是全局一致的,所以即使某个服务器失效了,也不会影响更新的结果和回溯。
4、更新顺序一致
zk保证所有的更新操作都是按序进行(底层通过TCP保证数据流的顺序),后请求的操作不会先于先请求的操作发生,所以操作记录也是按序保存的。

猜你喜欢

转载自blog.csdn.net/blwinner/article/details/53420194