本文目录
- zookeeper提供哪些功能
- zookeeper,怎么读
- 为什么要使用zookeeper有什么功能吗
- 如何启动ZooKeeper
- 如何使用zookeeper
- 什么是Zookeeper
- Zookeeper-Zookeeper可以干什么
- zookeeper是怎么配置的
- zookeeper 节点有什么用
zookeeper提供哪些功能
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
zookeeper,怎么读
zookeeper的读音:英:[ˈzuːkiːpə(r)]美:[ˈzuːkiːpər]意思是:n.动物园管理员; 例句:One zookeeper feeding. It’s time for dinner
为什么要使用zookeeper有什么功能吗
2006年的时候Google出了Chubby来解决分布一致性的问题(distributed consensus problem),所有集群中的服务器通过Chubby最终选出一个Master Server ,最后这个Master Server来协调工作。简单来说其原理就是:在一个分布式系统中,有一组服务器在运行同样的程序,它们需要确定一个Value,以那个服务器提供的信息为主/为准,当这个服务器经过n/2+1的方式被选出来后,所有的机器上的Process都会被通知到这个服务器就是主服务器 Master服务器,大家以他提供的信息为准。很想知道Google Chubby中的奥妙,可惜人家Google不开源,自家用。但是在2009年3年以后沉默已久的Yahoo在Apache上推出了类似的产品ZooKeeper,并且在Google原有Chubby的设计思想上做了一些改进,因为ZooKeeper并不是完全遵循Paxos协议,而是基于自身设计并优化的一个2 phase commit的协议,如图所示:ZooKeeper跟Chubby一样用来存放一些相互协作的信息(Coordination),这些信息比较小一般不会超过1M,在zookeeper中是以一种hierarchical tree的形式来存放,这些具体的Key/Value信息就store在tree node中。当有事件导致node数据,例如:变更,增加,删除时,Zookeeper就会调用 triggerWatch方法,判断当前的path来是否有对应的监听者(watcher),如果有watcher,会触发其process方法,执行process方法中的业务逻辑
如何启动ZooKeeper
Zookeeper的启动入口在org.apache.zookeeper.server.quorum.QuorumPeerMain。在这个类的main方法里进入了zookeeper的启动过程,首先我们会解析配置文件,即zoo.cfg和myid。这样我们就知道了dataDir和dataLogDir指向哪儿了,然后就可以启动日志清理任务了(如果配置了的话)。DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config.getDataDir(), config.getDataLogDir(), config.getSnapRetainCount(), config.getPurgeInterval());purgeMgr.start();接下来会初始化ServerCnxnFactory,这个是用来接收来自客户端的连接的,也就是这里启动的是一个tcp server。在Zookeeper里提供两种tcp server的实现,一个是使用java原生NIO的方式,另外一个是使用Netty。默认是java nio的方式,一个典型的Reactor模型。因为java nio编程并不是本文的重点,所以在这里就只是简单的介绍一下。//首先根据配置创建对应factory的实例:NIOServerCnxnFactory 或者 NettyServerCnxnFactoryServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();//初始化配置cnxnFactory.configure(config.getClientPortAddress(),config.getMaxClientCnxns());创建几个SelectorThread处理具体的数据读取和写出。先是创建ServerSocketChannel,bind等this.ss = ServerSocketChannel.open();ss.socket().setReuseAddress(true);ss.socket().bind(addr);ss.configureBlocking(false);然后创建一个AcceptThread线程来接收客户端的连接。这一部分就是处理客户端请求的模块了,如果遇到有客户端请求的问题可以看看这部分。接下来就进入初始化的主要部分了,首先会创建一个QuorumPeer实例,这个类就是表示zookeeper集群中的一个节点。初始化QuorumPeer的时候有这么几个关键点:1. 初始化FileTxnSnapLog,这个类主要管理Zookeeper中的操作日志(WAL)和snapshot。2. 初始化ZKDatabase,这个类就是Zookeeper的目录结构在内存中的表示,所有的操作最后都会映射到这个类上面来。3. 初始化决议validator(QuorumVerifier-》QuorumMaj) (其实这一步,是在配置)。这一步是从zoo.cfg的server.n这一部分初始化出集群的成员出来,有哪些需要参与投票(follower),有哪些只是observer。还有决定half是多少等,这些都是zookeeper的核心。在这一步,对于每个节点会初始化一个QuorumServer对象,并且放到allMembers,votingMembers,observingMembers这几个map里。而且这里也对参与者的个数进行了一些判断。4. leader选举 这一步非常重要,也是zookeeper里最复杂而最精华的一部分。
如何使用zookeeper
如何使用Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理,后面将会详细介绍 Zookeeper 能够解决的一些典型问题,这里先介绍一下,Zookeeper 的操作接口和简单使用示例。 常用接口列表客户端要连接 Zookeeper 服务器可以通过创建 org.apache.zookeeper. ZooKeeper 的一个实例对象,然后调用这个类提供的接口来和服务器交互。前面说了 ZooKeeper 主要是用来维护和监控一个目录节点树中存储的数据的状态,所有我们能够操作 ZooKeeper 的也和操作目录节点树大体一样,如创建一个目录节点,给某个目录节点设置数据,获取某个目录节点的所有子目录节点,给某个目录节点设置权限和监控这个目录节点的状态变化。
什么是Zookeeper
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。ZooKeeper包含一个简单的原语集, 提供Java和C的接口。ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在zookeeper-3.4.3\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。(概述图片来源: )外文名ZooKeeper类 别分布式系统的可靠协调系统所 属Hadoop的正式子项目特 点高效,可靠
Zookeeper-Zookeeper可以干什么
在Zookeeper的官 网上有这么一句话:ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 这大概描述了Zookeeper主要可以干哪些事情:配置管理,名字服务,提供分布式同步以及集群管理。那这些服务又到底是什么呢?我们为什么需要这样的服务?我们又为什么要使用Zookeeper来实现呢,使用Zookeeper有什么优势?接下来我会挨个介绍这些到底是什么,以及有哪些开源系统中使用了。配置管理在我们的应用中除了代码外,还有一些就是各种配置。比如数据库连接等。一般我们都是使用配置文件的方式,在代码中引入这些配置文件。但是当我们只有一种配置,只有一台服务器,并且不经常修改的时候,使用配置文件是一个很好的做法,但是如果我们配置非常多,有很多服务器都需要这个配置,而且还可能是动态的话使用配置文件就不是个好主意了。这个时候往往需要寻找一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣的都可以获得变更。比如我们可以把配置放在数据库里,然后所有需要配置的服务都去这个数据库读取配置。但是,因为很多服务的正常运行都非常依赖这个配置,所以需要这个集中提供配置服务的服务具备很高的可靠性。一般我们可以用一个集群来提供这个配置服务,但是用集群提升可靠性,那如何保证配置在集群中的一致性呢? 这个时候就需要使用一种实现了一致性协议的服务了。Zookeeper就是这种服务,它使用Zab这种一致性协议来提供一致性。现在有很多开源项目使用Zookeeper来维护配置,比如在HBase中,客户端就是连接一个Zookeeper,获得必要的HBase集群的配置信息,然后才可以进一步操作。还有在开源的消息队列Kafka中,也使用Zookeeper来维护broker的信息。在Alibaba开源的SOA框架Dubbo中也广泛的使用Zookeeper管理一些配置来实现服务治理。名字服务名字服务这个就很好理解了。比如为了通过网络访问一个系统,我们得知道对方的IP地址,但是IP地址对人非常不友好,这个时候我们就需要使用域名来访问。但是计算机是不能是别域名的。怎么办呢?如果我们每台机器里都备有一份域名到IP地址的映射,这个倒是能解决一部分问题,但是如果域名对应的IP发生变化了又该怎么办呢?于是我们有了DNS这个东西。我们只需要访问一个大家熟知的(known)的点,它就会告诉你这个域名对应的IP是什么。在我们的应用中也会存在很多这类问题,特别是在我们的服务特别多的时候,如果我们在本地保存服务的地址的时候将非常不方便,但是如果我们只需要访问一个大家都熟知的访问点,这里提供统一的入口,那么维护起来将方便得多了。
zookeeper是怎么配置的
(1)配置管理集中式的配置管理在应用集群中是非常常见的,一般商业公司内部都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。Zookeeper很容易实现这种集中式的配置管理,比如将APP1的所有配置配置到/APP1znode下,APP1所有机器一启动就对/APP1这个节点进行监控(zk.exist(“/APP1“,true)),并且实现回调方法Watcher,那么在zookeeper上/APP1znode节点下数据发生变化的时候,每个机器都会收到通知,Watcher方法将会被执行,那么应用再取下数据即可(zk.getData(“/APP1“,false,null));以上这个例子只是简单的粗颗粒度配置监控,细颗粒度的数据可以进行分层级监控,这一切都是可以设计和控制的。(2)集群管理应用集群中,我们常常需要让每一个机器知道集群中(或依赖的其他某一个集群)哪些机器是活着的,并且在集群机器因为宕机,网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。Zookeeper同样很容易实现这个功能,比如我在zookeeper服务器端有一个znode叫/APP1SERVERS,那么集群中每一个机器启动的时候都去这个节点下创建一个EPHEMERAL类型的节点,比如server1创建/APP1SERVERS/SERVER1(可以使用ip,保证不重复),server2创建/APP1SERVERS/SERVER2,然后SERVER1和SERVER2都watch/APP1SERVERS这个父节点,那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节点有一个很重要的特性,就是客户端和服务器端连接断掉或者session过期就会使节点消失,那么在某一个机器挂掉或者断链的时候,其对应的节点就会消失,然后集群中所有对/APP1SERVERS进行watch的客户端都会收到通知,然后取得最新列表即可。另外有一个应用场景就是集群选master,一旦master挂掉能够马上能从slave中选出一个master,实现步骤和前者一样,只是机器在启动的时候在APP1SERVERS创建的节点类型变为EPHEMERAL_SEQUENTIAL类型,这样每个节点会自动被编号,例如zk.create(“/testRootPath/testChildPath1“,“1“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);zk.create(“/testRootPath/testChildPath3“,“2“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);zk.create(“/testRootPath/testChildPath3“,“3“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);//创建一个子目录节点zk.create(“/testRootPath/testChildPath4“,“4“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(zk.getChildren(“/testRootPath“,false));打印结果:[testChildPath10000000000,testChildPath30000000001,testChildPath40000000003,testChildPath30000000002]zk.create(“/testRootPath“,“testRootData“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);//创建一个子目录节点zk.create(“/testRootPath/testChildPath1“,“1“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);zk.create(“/testRootPath/testChildPath3“,“2“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);zk.create(“/testRootPath/testChildPath3“,“3“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);//创建一个子目录节点zk.create(“/testRootPath/testChildPath4“,“4“.getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);System.out.println(zk.getChildren(“/testRootPath“,false));打印结果:[testChildPath3,testChildPath1,testChildPath4,testChildPath3]我们默认规定编号最小的为master,所以当我们对/APP1SERVERS节点做监控的时候,得到服务器列表,只要所有集群机器逻辑认为最小编号节点为master,那么master就被选出,而这个master宕机的时候,相应的znode会消失,然后新的服务器列表就被推送到客户端,然后每个节点逻辑认为最小编号节点为master,这样就做到动态master选举。
zookeeper 节点有什么用
ZooKeeper 节点是有生命周期的,这取决于节点的类型。在 ZooKeeper 中,节点类型可以分为持久节点(PERSISTENT )、临时节点(EPHEMERAL),以及时序节点(SEQUENTIAL ),具体在节点创建过程中,一般是组合使用,可以生成以下 4 种节点类型。持久节点(PERSISTENT)所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。持久顺序节点(PERSISTENT_SEQUENTIAL)这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。临时节点(EPHEMERAL)和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。临时顺序节点(EPHEMERAL_SEQUENTIAL)可以用来实现分布式锁客户端调用create()方法创建名为“_locknode_/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。客户端调用getChildren(“_locknode_”)方法来获取所有已经创建的子节点,注意,这里不注册任何Watcher。客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点序号最小,那么就认为这个客户端获得了锁。如果在步骤3中发现自己并非所有子节点中最小的,说明自己还没有获取到锁。此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时注册事件监听。之后当这个被关注的节点被移除了,客户端会收到相应的通知。这个时候客户端需要再次调用getChildren(“_locknode_”)方法来获取所有已经创建的子节点,确保自己确实是最小的节点了,然后进入步骤3。