yield-bytes

沉淀、分享与无限进步

ZooKeeper特性适用的应用场景

  随着对zk使用和了解更深入,不得不佩服Apache基金出品的技术,一直拥有着改变世界的能量!zookeeper结合大数据技术栈,实现无以伦比的高可用分布式大数据架构,单单这一点就非常让人兴奋,从zk的设计来看,传统的数据结构和算法以及底层网络知识和技术,仍然可以通过结合现代业务模型进行创造和创新,所有继续保持沉淀传统基础,以助力更高效吸收新技术!

  以下引用了网上一些对zk的总结,内容比较简单,毕竟不是原理探讨,但对于zk的特性使用或者说发挥zk的特长,需要开发者深度理解数据模型或应用场景才能实现基于zk特性的相应逻辑。一些常用的zk特性和场合说明整理放在个人blog上,以便查阅

数据发布与订阅(配置中心)

  数据发布与订阅,即所谓的配置中心,顾名思义就是发布者将数据发布到ZooKeeper节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和动态更新。
  类似这样的需求:系统中需要使用一些通用的配置信息,例如机器列表信息、数据库配置信息等。这些全局配置信息通常具备以下3个特性。

  • 数据量通常比较小
  • 数据内容在运行时动态变化。
  • 集群中各机器共享,配置一致。

对于这样的全局配置信息就可以发布到ZooKeeper上,让客户端(集群的机器)去订阅该消息。

发布/订阅系统一般有两种设计模式,分别是推(Push)和拉(Pull)模式。

  • 推:服务端主动将数据更新发送给所有订阅的客户端。
  • 拉:客户端主动发起请求来获取最新数据,通常客户端都采用定时轮询拉取的方式。

  ZooKeeper采用的是推拉相结合的方式。如下:
客户端想服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据(推拉结合)。

Naming Service

  命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体通常可以是集群中的机器,提供的服务,远程对象等等——都可以统称他们为名字(Name)。其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表。通过在ZooKeepr里创建顺序节点,能够很容易创建一个全局唯一的路径,这个路径就可以作为一个名字。
==ZooKeeper的命名服务即生成全局唯一的ID==

分布式协调/通知

  ZooKeeper中特有Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至不同系统之间的通知与协调,从而实现对数据变更的实时处理。使用方法通常是不同的客户端都对ZK上同一个ZNode进行注册,监听ZNode的变化(包括ZNode本身内容及子节点的),如果ZNode发生了变化,那么所有订阅的客户端都能够接收到相应的Watcher通知,并做出相应的处理。
==ZK的分布式协调/通知,是一种通用的分布式系统机器间的通信方式。==

心跳检测

  基于ZK的临时节点的特性,可以让不同的进程都在ZK的一个指定节点下创建临时子节点,不同的进程直接可以根据这个临时子节点来判断对应的进程是否存活。通过这种方式,检测和被检测系统直接并不需要直接相关联,而是通过ZK上的某个节点进行关联,大大减少了系统耦合。

工作进度汇报

  在一个常见的任务分发系统中,通常任务被分发到不同的机器上执行后,需要实时地将自己的任务执行进度汇报给分发系统。这个时候就可以通过ZK来实现。在ZK上选择一个节点,每个任务客户端都在这个节点下面创建临时子节点,这样便可以实现两个功能:

  • 通过判断临时节点是否存在来确定任务机器是否存活。
  • 各个任务机器会实时地将自己的任务执行进度写到这个临时节点上去,以便中心系统能够实时地获取到任务的执行进度。

Master选举

  Master选举可以说是ZooKeeper最典型的应用场景了。比如HDFS中Active NameNode的选举、YARN中Active ResourceManager的选举和HBase中Active HMaster的选举等。

  利用ZooKeepr的强一致性,能够很好地保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,即ZooKeeper将会保证客户端无法创建一个已经存在的ZNode。也就是说,如果同时有多个客户端请求创建同一个临时节点,那么最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很容易地在分布式环境中进行Master选举了。

  成功创建该节点的客户端所在的机器就成为了Master。同时,其他没有成功创建该节点的客户端,都会在该节点上注册一个子节点变更的Watcher,用于监控当前Master机器是否存活,一旦发现当前的Master挂了,那么其他客户端将会重新进行Master选举。

分布式锁

  分布式锁是控制分布式系统之间同步访问共享资源的一种方式。分布式锁又分为排他锁和共享锁两种。

排他锁

排他锁(Exclusive Locks,简称X锁),又称为写锁或独占锁。

如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能在对这个数据对象进行任何类型的操作(不能再对该对象加锁),直到T1释放了排他锁。

可以看出,排他锁的核心是如何保证当前只有一个事务获得锁,并且锁被释放后,所有正在等待获取锁的事务都能够被通知到。

排他锁流程

定义锁

ZooKeeper上的一个znode可以表示一个锁。例如/exclusive_lock/lock节点就可以被定义为一个锁。

获得锁

  如上所说,把ZooKeeper上的一个ZNode看作是一个锁,获得锁就通过创建znode的方式来实现。所有客户端都去/exclusive_lock节点下创建临时子节点/exclusive_lock/lock。ZooKeeper会保证在所有客户端中,最终只有一个客户端能够创建成功,那么就可以认为该客户端获得了锁。同时,所有没有获取到锁的客户端就需要到/exclusive_lock节点上注册一个子节点变更的Watcher监听,以便实时监听到lock节点的变更情况。

释放锁

  因为/exclusive_lock/lock是一个临时节点,因此在以下两种情况下,都有可能释放锁。

  • 当前获得锁的客户端机器发生宕机或重启,那么该临时节点就会被删除,释放锁。
  • 正常执行完业务逻辑后,客户端就会主动将自己创建的临时节点删除,释放锁。

  无论在什么情况下移除了lock节点,ZooKeeper都会通知所有在/exclusive_lock节点上注册了节点变更Watcher监听的客户端。这些客户端在接收到通知后,再次重新发起分布式锁获取,即重复『获取锁』过程。

共享锁(也就是zk上实现的分布式锁)

  可以多个事务同时获得一个对象的共享锁(同时读),有共享锁就不能再加排他锁(因为排他锁是写锁),前面已经在文章给出基于分布式锁的非常详细的实现过程,这里不再重复。