zookeeper简介

在介绍这个项目之前先来看看我们需要解决什么问题:

有这样一个一个场景:有一组服务器来为客户端提供某种服务,每个客户端都需要找到其中的一台服务器来使用其服务,问题是:客户端如何能找到这组服务器呢?

我们可以选择找一个服务器来存储这组服务器的列表,但如何保证这组列表的可用性?即如果存储服务器列表的服务器坏了怎么办?

接上一个场景:如果我们找到了一个地方来存储这组服务器的列表,以至于每个客户端都能获取这个服务器列表,这很好,但是如果这组服务器(注意,不是提供服务器列表的服务器,而是为客户端提供服务的服务器)中有一个服务器坏掉了怎么办?

如果不能及时更新这个服务器列表的话,客户端可能连接到一个不可用的服务器上。这里需要注意的是,服务器不可用的情况有很多种,最有可能的就是直接断电了,所以靠服务器本身来更新服务器列表是不可行的。

以上两个问题可以由zookeeper轻易的解决,解决了以上问题,我们就有了一个相对可靠的能对外提供服务的分布式环境了。

下面进入正文

1、目的

zookeeper是为了解决分布式环境下出现的一些 部分失败(partial failure)的问题而产生的。所谓部分失败就是在一次完整的请求时,由于请求了不可用的节点而导致这部分请求失败,是分布式系统固有的问题。zookeeper提供了对使用者透明的方式来管理各服务器,正如她的名字zoo keeper 一个动物园,用来管理动物的(服务器).

2、核心

zookeeper的核心在于一个精简的文件系统,她提供了一组简单的API来操作这个“文件系统”的“目录”,并且提供对这些“目录”状态的监听接口,以便在这些目录的状态发生变化时各个观察者能很快的接收到这些变化。

具体说来在zookeeper中这些目录叫做znode,znode既可以保存一些数据(类似于文件系统中的文件)也可以保存其他的znode(类似于目录的功能),这样就形成了一个树形结构。这个结构可以用来表示完整的服务器列表,并且她是高可用的,原因在于zookeeper支持多节点部署,在某个zookeeper服务器坏掉之后亦不会损坏数据。此处就解决了上述的第一个场景的问题。

3、架构

zkservice

zookeeper server提供一些接口给client,client可以是java程序,C程序,也可以是命令行程序,基于这种架构,每个客户端可以对zookeeper server上的数据(即之前提到的目录树)进行操作,支持的操作有:

create:创建一个znode(不可级联创建)
delete:删除一个znode(不能删除含有子节点的node)
exists:判断一个znode是否存在
getACL,setACL:权限相关的操作
getChildren:获取一个znode的子节点列表
getData,setData:znode保存的数据相关操作
sync:将客户端的znode视图与zookeeper同步

4、znode

瞬时节点(Ephemeral Nodes):创建本节点的zookeeper客户端会话结束时,zookeeper会自动将节点删除。此类节点可用来让任何客户端时刻知道有哪些服务器可用,只需要判断服务器所创建的节点是不是存在就可以了。这就解决了上边第二个场景的问题。

顺序节点(Sequence Nodes):在请求创建的节点名后追加一个序列号,如客户端请求创建/a/b-节点,则创建的节点可能实际上是/a/b-3,若再有客户端创建/a/b-的节点,则可能实际创建的节点为/a/b-7。此类节点一般用来标识一些事件,并可进行全局排序。

观察机制(Watch):对某个znode进行观察(watch),这样可以在znode的状态发生变化的时候得到这个变化。

1、通过使用这种机制,我们可以令客户端观察相关服务器所创建的瞬时节点,如果服务器宕机,则瞬时节点消失,那么客户端通过观察就能被动的接收到这个事件,并进行相应处理。

2、还有一种就是用来进行配置文件的动态修改,即通过修改某个znode的数据(键值对),来通知所有需要这个znode上相关数据的客户端(服务器)来达到配置文件的动态修改。

 5、分布式锁

若一个分布式系统中在同一时间提供某种服务的服务器只能有一个,那么如何保证在这台服务器死掉之后能马上有其他的服务器来接替它的工作呢?并且在这台服务器没死掉的时候不能有别人来处理相应的服务?

这里就有某一个服务器获取了这个分布式锁的概念了。一个简单的实现是:对每个需要获得锁的服务都在某个znode下创建一个瞬时节点,当这个服务所创建的瞬时节点为这个znode下的所有瞬时节点中最小(Sequence)的一个时,其获得分布式锁,而每一个想要获得锁的服务都需要去Watch这个znode的状态,观察其子节点的变化。(这里依赖于后创建的节点一定比先创建的节点大)。

对于上边的简单实现会存在一些细节问题:zookeeper的源码包里已经提供了一个用java写的实现,可用于生产环境。

 6、通过java API进行一些操作

 ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT,
        ClientBase.CONNECTION_TIMEOUT, new Watcher() {
            // 监控所有被触发的事件
            public void process(WatchedEvent event) {
                System.out.println("已经触发了" + event.getType() + "事件!");
            }
        });
 // 创建一个目录节点
 zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,
   CreateMode.PERSISTENT);
 // 创建一个子目录节点
 zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(),
   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
 System.out.println(new String(zk.getData("/testRootPath",false,null)));
 // 取出子目录节点列表
 System.out.println(zk.getChildren("/testRootPath",true));
 // 修改子目录节点数据
 zk.setData("/testRootPath/testChildPathOne","modifyChildDataOne".getBytes(),-1);
 System.out.println("目录节点状态:["+zk.exists("/testRootPath",true)+"]");
 // 创建另外一个子目录节点
 zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(),
   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
 System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo",true,null)));
 // 删除子目录节点
 zk.delete("/testRootPath/testChildPathTwo",-1);
 zk.delete("/testRootPath/testChildPathOne",-1);
 // 删除父目录节点
 zk.delete("/testRootPath",-1);
 // 关闭连接
 zk.close();

7、部署

单机环境部署很简单,并且支持win平台下的开发环境部署,只需要将/conf/zoo_sample.cfg重命名为zoo.cfg就可以了,必要的参数为

tickTime=2000#心跳时间
dataDir=/var/lib/zookeeper#数据目录
clientPort=2181#服务端口

之后就可运行/bin/zkServer.sh或zkServer.cmd来启动zookeeper了,集群环境部署也很简单可参考http://zookeeper.apache.org/doc/trunk/zookeeperAdmin.html#sc_zkMulitServerSetup进行安装。

值得一提的是zookeeper本身提供了一个用shell来连接到其目录树上,我们可以通过这个shell来进行简单的操作,单机下只需要运行/bin/zkCli.sh或zkCli.cmd即可。在这个shell下支持的相关操作如下,对于开发或维护时都很方便:

get path [watch]
ls path [watch]
set path data [version]
delquota [-n|-b] path
quit
printwatches on|off
createpath data acl
stat path [watch]
listquota path
history
setAcl path acl
getAcl path
sync path
redo cmdno
addauth scheme auth
delete path [version]
deleteall path
setquota -n|-b val path

注:运行以上脚本需要java环境支持

以上即为zookeeper简介,还有很多未提到的功能,如权限ACL、队列的应用等;并且更深入一些的实现原理也没有介绍,实在是精力不够。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注