Zookeeper(一)简介

     ZooKeeper是一个高可用的分布式数据管理与系统协调框架。基于对Paxos算法的实现,提供了一系列原语集,更上层的应用可以用它来实现同步,配置管理,名称服务,Master选举,分布式锁,分布式队列等使该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题。

一、zookeeper提供如下服务保证

顺序一致性: clientupdates请求都会根据它发出的顺序被顺序的处理

原子性: 一个update操作要么成功要么失败,没有其他可能的结果

一致性的镜像: client不论连接到哪个server,展示给它都是同一个视图

可靠性: 一旦一个update被应用就被持久化了,除非另一个update请求更新了当前值

及时性: 客户端所看到的系统在一个时间范围内是最新的

 

二、zookeeper的设计目标

1. 简单

    ZooKeeper允许分布式进程之间通过一个共享的层级命名空间来相互协作,这个命名空间以类似于文件系统的方式组织起来。命名空间中的数据单元被称为znode,它相当于文件或者目录。与典型文件系统不同的是,文件系统用于持久化存储,而ZooKeeper的数据是保持在内存中的,这意味着ZooKeeper能达到很高的吞吐量和低延迟。

2. 高性能、高可用性,和严格的顺序访问

    高性能使得ZooKeeper能用于大规模分布式系统,高可用性能避免单点故障,严格的顺序化意味着复杂的同步操作可以在客户端实现。

3. 集群化

ZooKeeper本身也是有集群化的。如下图:

Zookeeper(一)简介_第1张图片

 

      客户端与单个服务端相连,它维持一个TCP连接,在其上发送请求,获得响应,获得监控事件和发送心跳检测。如果到服务端的TCP连接断了,客户端会连接另一个服务端。组成ZooKeeper服务的每个服务端都知道其它服务端的存在,它们维护一个服务端状态的内存镜像,连同事务日志和快照保存在持久化存储中,只要大部分服务端可用,ZooKeeper服务就可用。

4. 顺序化

    ZooKeeper为每个更新操作都标记一个号码以反映事务的顺序。后来的操作使用这个顺序来实现高度的抽象,比如同步原语。

5. 快速

     这个特性在以读操作为主的工作中尤为明显。ZooKeeper应用程序运行于数以千计的机器中,当读操作与写操作的比例为10:1时,ZooKeeper能获得最佳性能。

三、ZooKeeper的常见应用场景

1. 命名服务(Naming Service)

     命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体通常可以是集群中的机器,提供的服务地址,远程对象等等——这些我们都可以统称他们为名字(Name)。其中较为常见的就是一些分布式服务框架中的服务地址列表。通过调用ZK提供的创建节点的API,能够很容易创建一个全局唯一的znode,所有应用从中读取,避免写死。

2. 分布式通知/协调

    ZooKeeper中特有watcher注册与异步通知机制,能够很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理。使用方法通常是不同系统都对ZK上同一个znode进行注册,监听znode的变化(包括znode本身内容及子节点的),其中一个系统updateznode,那么另一个系统能够收到通知,并作出相应处理

3. 分布式锁

    这个主要得益于ZooKeeper为我们保证了数据的强一致性。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

     所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现。所有客户端都去创建/distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。

控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。Zk的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而也形成了每个客户端的全局时序。

4. 分布式队列

     简单地讲有两种,一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行。对于第一种先进先出队列,和分布式锁服务中的控制时序场景基本原理一致,这里不再赘述。

     第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在 /queue 这个znode下预先建立一个/queue/num 节点,并且赋值为n(或者直接给/queue赋值n),表示队列大小,之后每次有队列成员加入后,就判断下是否已经到达队列大小,决定是否可以开始执行了。这种用法的典型场景是,分布式环境中,一个大任务Task A,需要在很多子任务完成(或条件就绪)情况下才能进行。这个时候,凡是其中一个子任务完成(就绪),那么就去 /taskList 下建立自己的临时时序节点(CreateMode.EPHEMERAL_SEQUENTIAL),当 /taskList 发现自己下面的子节点满足指定个数,就可以进行下一步按序进行处理了。

四、总结

   zookeeper的设计思想很好,实现解决了很多问题,尤其在分布式,保持服务稳定性方面,提供了很多支持,使得提供稳定的服务变成了可能。后续博客会继续介绍zookeeper,敬请期待。

 

你可能感兴趣的:(Zookeeper(一)简介)