Zookeeper是一个针对大型分布式系统的可靠协调系统。提供的功能包括:配置维护、名字服务、分布式同步、组服务等。目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。Zookeeper已经成为Hadoop生态系统中的基础组件。
Zookeeper有如下特点:
最终一致性:为客户端展示同一视图,这是zookeeper最重要的功能。
可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
实时性:Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
等待无关(wait-free):慢的或者失效的client不干预快速的client的请求。
原子性:更新只能成功或者失败,没有中间状态。
顺序性:所有Server,同一消息发布顺序一致。
Zookeeper的应用有HDFS、YARN、Storm、HBase、Flume、Dubbo(阿里巴巴)以及metaq阿里巴巴)。
Zookeeper基本原理
Zookeeper的架构如图所示。
每个Server在内存中存储了一份数据。当Zookeeper启动时,将从实例中选举一个leader(Paxos协议)。Leader负责处理数据更新等操作(Zab协议)。一个更新操作成功,当且仅当大多数Server在内存中成功修改数据。
Zookeeper有三个不同的角色。领导者负责进行投票的发起和决议以及系统的状态更新。学习者包括跟随者和观察者。其中,跟随者用于接收客户请求并向客户端返回结果,在选主过程中参与投票。观察者可以接收客户端连接,将写请求转发给leader节点。但观察者不参与投票,只负责同步leader的状态。目的是为了系统的扩展,提高读取速度。客户端是请求发起方。
Leader选举算法采用了Paxos协议。Paxos的核心思想是当多数Server写成功,则任务数据写成功。如果有3个Server,则两个写成功即可。
Zookeeper的写过程如图所示。首先,客户端向本地server发送请求。然后,server向leader发送请求,leader会向各个server发起投票命令。之后,leader会收集投票结果通知所有server秃瓢结果。最后,server发送操作结果给客户端。
Zookeeper的数据模型
Zookeeper是层次化的目录结构,命名符合常规文件系统规范。每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识。节点Znode可以包含数据和子节点(EPHEMERAL类型的节点不能有子节点)。Znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据需带上版本。客户端应用可以在节点上设置监视器(Watcher)。节点不支持部分读写,而是一次性完整读写。Znode有两种类型,短暂的(ephemeral)和持久的(persistent)。Znode的类型在创建时确定并且之后不能再修改。短暂znode的客户端会话结束时,zookeeper会将该短暂znode删除,短暂znode不可以有子节点。持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除。Znode有四种形式的目录节点,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL。
Zookeeper应用场景
统一命名服务
分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务。类似于域名与ip之间对应关系,域名容易记住。通过名称来获取资源或服务的地址,提供者等信息按照层次结构组织服务/应用名称可将服务名称以及地址信息写到Zookeeper上,客户端通过Zookeeper获取可用服务列表类。
配置管理
分布式环境下,配置文件管理和同步是一个常见问题。一个集群中,所有节点的配置信息是一致的,比如Hadoop。对配置文件修改后,希望能够快速同步到各个节点上配置管理可交由Zookeeper实现。可将配置信息写入Zookeeper的一个znode上。各个节点监听这个znode。一旦znode中的数据被修改,zookeeper将通知各个节点。
集群管理
分布式环境中,实时掌握每个节点的状态是必要的。可根据节点实时状态作出一些调整。Zookeeper可将节点信息写入Zookeeper的一个znode上。监听这个znode可获取它的实时状态变化。典型应用比如Hbase中Master状态监控与选举。
分布式通知/协调
分布式环境中,经常存在一个服务需要知道它所管理的子服务的状态。例如,NameNode须知道各DataNode的状态,JobTracker须知道各TaskTracker的状态。心跳检测机制和信息推送也是可通过Zookeeper实现。
分布式锁
Zookeeper是强一致的。多个客户端同时在Zookeeper上创建相同znode,只有一个创建成功。Zookeeper实现锁的独占性。多个客户端同时在Zookeeper上创建相同znode ,创建成功的那个客户端得到锁,其他客户端等待。Zookeeper 控制锁的时序。各个客户端在某个znode下创建临时znode (类型为CreateMode. EPHEMERAL _SEQUENTIAL),这样,该znode可掌握全局访问时序。
分布式队列
两种队列。当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型。(可通过分布式锁实现)
同步队列。一个job由多个task组成,只有所有任务完成后,job才运行完成。可为job创建一个/job目录,然后在该目录下,为每个完成的task创建一个临时znode,一旦临时节点数目达到task总数,则job运行完成。
Zookeeper客户端设计
Zookeeper API包括:
String create (path, data, acl, flags)
void delete (path, expectedVersion)
Stat setData (path, data, expectedVersion)
byte[] getData (path, watch)
Stat exists (path, watch)
String[] getChildren (path, watch)
void sync (path)
Zookeeper Watcher
Watcher 在 ZooKeeper 是一个核心功能。可以监控目录节点的数据变化以及子目录的变化。一旦状态发生变化,服务器就会通知所有设置在这个目录节点上的 Watcher。其基本特点是一次设置对应一次触发、异步触发以及顺序触发。可以设置观察的操作为exists getChildren getData。可以触发观察的操作为create delete setData。
Zookeeper案例—配置管理(Updater设计)
Zookeeper案例—配置管理(Wacher设计)
以上介绍了Zookeeper的基本原理与应用场景,下一步将介绍hadoop的其他组件。