这里没有太多的分析,只是做为一些简单配置及安装记录,生怕自己忘记了。
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop的重要组件,CDH版本中更是使用它进行Namenode的协调控制。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,提供简单易用的接口和性能高效、功能稳定的系统提供给用户。分布式应用程序可以基于它实现同步服务,配置维护和命名服务等
分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种临界资源,防止造成"脏数据"的后果。
客户端请求处理器(requestprocessor),构成ZooKeeper服务的每个服务器都有一个备份。复制的数据库(replicateddatabase)是一个内存数据库,包含整个数据树。为了可恢复,更新会被log到磁盘,并且在更新这个内存数据库之前,先序列化到磁盘。
每个ZooKeeper都为客户端提供服务。客户端只连接到一个服务器,并提交请求。读请求直接由本地的复制数据库提供数据。对服务状态进行修改的请求、写请求通过一个约定的协议进行通讯。
作为这个协议的一部分,所有的写请求都被传送到一个叫“首领(leader)”的服务器,而其他的服务器,叫做“(随从)followers”,follower从leader接收信息修改的提议,并同意进行。当leader发生故障时,协议的信息层(messaginglayer)关注leader的替换,并同步到所有的follower。
ZooKeeper采用一个自定义的信息原子操作协议zab,由于信息层的操作是原子性的,ZooKeeper能保证本地的复制数据库不会产生不一致。当leader接收到一个写请求,它计算出写之后系统的状态,把它变成一个事务(二次提交协议)
Zookeeper是一个由多个server组成的集群一个leader,多个follower
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:
通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.
每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。
fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。
转载自http://blog.csdn.net/a807557328/article/details/78016928
从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,ZooKeeper树中的每个节点被称为—Znode
zk的数据模型从结构上看似和Linux系统的文件系统相似,但是zk的znode节点非常却非常的不同。
Zonde通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变,所以zk并没有相对路径存在。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。
zk对路径的命名有一些要求,几乎所有的unicode编码都适用,除了以下几点:
ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:
ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小一般在kb大小,至多1M,但常规使用中应该远小于此值。如果需要存储大型数据,建议将数据存放在hdfs等文件存储系统
ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。
节点类型有四种,分别是PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL,分别为永久节点,永久有序节点,临时节点和临时有序节点。节点的类型在创建时即被确定,并且不能改变。
客户端可以在节点上设置watch,我们称之为监视器。当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量。
查看node2节点的信息“get /node2”
[zk: 127.0.0.1:2181(CONNECTED) 2] get /node2
sdffff
cZxid = 0x200000007
ctime = Thu Dec 07 16:37:55 CST 2017
mZxid = 0x2400000006
mtime = Mon Dec 18 10:57:16 CST 2017
pZxid = 0x2400000004
cversion = 4
dataVersion = 8
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 2
zxid
致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。也就是说,也就是说,每个对节点的改变都将产生一个唯一的Zxid。 每次节点的变更都会有一个自增票戳(stamp),例如0x200000009、0x20000000a、0x20000000b。
ZooKeeper的每个节点维护者三个Zxid值为别为:cZxid、mZxid、pZxid
实现中Zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位是个递增计数。
version
对节点的任何变更,都会触发版本的升级,包括三个:
time
zk并没有使用真正的时间,而是存储相对与起始(epoch)的毫秒数,包括两个:—有疑问?
ctime:创建时的毫秒数
mtime:距离上次修改的毫秒数
ephemeralOwner
如果是ephemeral node节点,将会存储session id,否则存储为0;zk服务器会依据这个session id判断是否删除该临时节点。
dataLength:当前节点存储的数据长度;
numChildren:当前节点的子节点个数;
(1) watch概述
ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()、getChildren()及getData()。watch事件是一次性的触发器,当watch的对象状态发生改变时,将会触发此对象上watch所对应的事件。watch事件将被异步地发送给客户端,并且ZooKeeper为watch机制提供了有序的一致性保证。理论上,客户端接收watch事件的时间要快于其看到watch对象状态变化的时间。
(2) watch类型
ZooKeeper所管理的watch可以分为两类:
① 数据watch(data watches):getData和exists负责设置数据watch
② 孩子watch(child watches):getChildren负责设置孩子watch
我们可以通过操作返回的数据来设置不同的watch:
① getData和exists:返回关于节点的数据信息
② getChildren:返回孩子列表
因此
① 一个成功的setData操作将触发Znode的数据watch
② 一个成功的create操作将触发Znode的数据watch以及孩子watch
③ 一个成功的delete操作将触发Znode的数据watch以及孩子watch
(3) watch注册与处触发
Watch由客户端所连接的ZooKeeper服务器在本地维护,因此watch可以非常容易地设置、管理和分派。当客户端连接到一个新的服务器时,任何的会话事件都将可能触发watch。另外,当从服务器断开连接的时候,watch将不会被接收。但是,当一个客户端重新建立连接的时候,任何先前注册过的watch都会被重新注册。
(4) 需要注意的几点
Zookeeper的watch实际上要处理两类事件:
① 连接状态事件(type=None, path=null)
这类事件不需要注册,也不需要我们连续触发,我们只要处理就行了。
② 节点事件
节点的建立,删除,数据的修改。它是one time trigger,我们需要不停的注册触发,还可能发生事件丢失的情况。
上面2类事件都在Watch中处理,也就是重载的process(Event event)
节点事件的触发,通过函数exists,getData或getChildren来处理这类函数,有双重作用:
① 注册触发事件
② 函数本身的功能
触发只能一次触发,这个zk触发器的设计,这样可以减少网络流量,但是在我们使用中可以循环的去监听事件。所幸的是我们本身不用去写for循环之类的循环监听。而是通过zk提供的api来设置一个参数就OK了。
上面说的都是zk的本质,在使用过程中可以使用zkclient第三方的jar包,将大大简化我们的操作。
//使用zk原生的api,当设置为true时,则表示一直监听,如果为false则只会监听一次。
zooKeeper.getData(watchedEvent.getPath(), true, stat)
//使用zkclient订阅节点的变化,无须设置true或 false直接一直监听子节点的变化
zkClient.subscribeChildChanges("/node2", new ZkChildListener());
1.官网下载zookeeper
2.新建一个文件夹service(可以自己随意),将zookeeper解压到service文件夹下
3.进入到/service/zookeeper/conf这个目录
3.在conf目录下复制zoo_sample.cfg文件,改名为zoo.cfg,删除zoo_sample.cfg文件。
4.修改zook.cfg
tickTime=2000
dataDir=/service/data
dataLogDir=/service/dataLog
clientPort=2181
伪集群部署和集群部署差不多,只不过伪集群是在同一台机器上面部署多个zk。
service1文件夹下:
在service1文件夹下的data下面创建一个文件myid(没有后缀哦)里面填写1
tickTime=2000
clientPort=2181
dataDir=/service1/data
dataLogDir=/service1/dataLog
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
service2文件夹下:
在service2文件夹下的data下面创建一个文件myid(没有后缀哦)里面填写2
tickTime=2000
##修改一下端口
clientPort=2182
dataDir=/service2/data
dataLogDir=/service2/dataLog
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
service3下类似就OK了。
进入到/service1/zookeeper/bin目录下启动service1
./zkServer.sh start
同样进入到/service2/zookeeper/bin目录下启动service2.
检查service是否启动成功。
echo stat|nc 127.0.0.1 2181
集群配置
(1) initLimit
此配置表示,允许follower(相对于Leaderer言的“客户端”)连接并同步到Leader的初始化连接时间,以tickTime为单位。当初始化连接时间超过该值,则表示连接失败。
(2) syncLimit
此配置项表示Leader与Follower之间发送消息时,请求和应答时间长度。如果follower在设置时间内不能与leader通信,那么此follower将会被丢弃。
(3) server.number=ip:leaderPort:zkPort
如:server.3=127.0.0.1:2890:3890
A:其中numbe是一个数字,表示这个是服务器的编号,从myid中的值对应
B:ip是这个服务器的 ip 地址;
C:leaderPort为Leader选举的端口;
D:zkPort为Zookeeper服务器之间的通信端口。
(4) myid和zoo.cfg
除了修改 zoo.cfg 配置文件,集群模式下还要配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面就有一个数据就是 A 的值,Zookeeper 启动时会读取这个文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是那个 server。
搭建要求:
nc为netcat命令的简写
echo stat | nc localhost 2181
conf: 输出相关服务配置的详细信息。
cons: 列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。包括“接受 / 发送”的包数量、会话 id 、操作延迟、最后的操作执行等等信息。
dump: 列出未经处理的会话和临时节点。
envi: 输出关于服务环境的详细信息(区别于 conf 命令)。
reqs: 列出未经处理的请求
ruok: 测试服务是否处于正确状态。如果确实如此,那么服务返回“ imok ”,否则不做任何相应。
stat: 输出关于性能和连接的客户端的列表。
wchs: 列出服务器 watch 的详细信息。
wchc: 通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
wchp: 通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。
crst: 重置当前这台服务器所有连接/会话的统计信息
srst: 重置服务器的统计信息
srvr: 输出服务器的详细信息。zk版本、接收/发送包数量、连接数、模式(leader/follower)、节点总数。
还可以使用telnet查看是否启动成功
telnet 10.1.101.162 2181连接后按回车,然后输入四字命令
进入到/server1/zookeeper/bin目录下面可以看到一个叫zkCli.sh的工具
./zkCli.sh -timeout 5000 -server 127.0.0.1:2181
进入到service1的zk的shell控制台中。
敲入:h查看帮助,会看到有10多个简单的命令,看帮助文档也知道它的使用了。
查看/节点
ls /
查看/节点状态
stat /
创建节点(必须是全路径,后面必须有值才能创建成功)
create /node1 111
创建子节点
create /node1/node1.1 11222
获取节点信息
get /node1/node1.1
创建一个有序节点
create -s /node2 222
创建一个临时节点
create -e /node2 222
临时节点会在与客户端连接断开后,自动删除
创建一个有序的临时节点
create -e -s /node2 3dsf
修改一个节点的值
set /node2 3333
taokeeper;exhibitor
exhibitor的github下载源代码 https://github.com/Netflix/exhibitor,下载zip包。
经过使用exhibitor好难用。
主要有:命名服务,分布式锁,分布式队列,master选举服务等。
对zk的应该基本都是应该了zk的znode的特点:节点唯一性;临时节点自动删除;有序节点。
详细请参看
http://www.cnblogs.com/sunddenly/p/4092654.html
我自己的代码实现可以参看
https://github.com/henjuese/zookeeperDemo.git
在Java API中的每一个ZooKeeper操作都在其throws子句中声明了两种类型的异常,分别是InterruptedException和KeeperException。
如果操作被中断,则会有一个InterruptedException异常被抛出。在Java语言中有一个取消阻塞方法的标准机制,即针对存在阻塞方法的线程调用interrupt()。一个成功的取消操作将产生一个InterruptedException异常。
ZooKeeper也遵循这一机制,因此你可以使用这种方法来取消一个ZooKeeper操作。使用了ZooKeeper的类或库通常会传播InterruptedException异常,使客户端能够取消它们的操作。InterruptedException异常并不意味着有故障,而是表明相应的操作已经被取消,所以在配置服务的示例中,可以通过传播异常来中止应用程序的运行。
(1) 如果ZooKeeper服务器发出一个错误信号或与服务器存在通信问题,抛出的则是KeeperException异常。
①针对不同的错误情况,KeeperException异常存在不同的子类。
例如: KeeperException.NoNodeException是KeeperException的一个子类,如果你试图针对一个不存在的znode执行操作,抛出的则是该异常。
②每一个KeeperException异常的子类都对应一个关于错误类型信息的代码。
例如: KeeperException.NoNodeException异常的代码是KeeperException.Code.NONODE
(2) 有两种方法被用来处理KeeperException异常:
①捕捉KeeperException异常,并且通过检测它的代码来决定采取何种补救措施;
②另一种是捕捉等价的KeeperException子类,并且在每段捕捉代码中执行相应的操作。
① 状态异常
当一个操作因不能被应用于znode树而导致失败时,就会出现状态异常。状态异常产生的原因通常是在同一时间有另外一个进程正在修改znode。例如,如果一个znode先被另外一个进程更新了,根据版本号执行setData操作的进程就会失败,并收到一个KeeperException.BadVersionException异常,这是因为版本号不匹配。程序员通常都知道这种冲突总是存在的,也都会编写代码来进行处理。
一些状态异常会指出程序中的错误,例如KeeperException.NoChildrenForEphemeralsException异常,试图在短暂znode下创建子节点时就会抛出该异常。
② 可恢复异常
可恢复的异常是指那些应用程序能够在同一个ZooKeeper会话中恢复的异常。一个可恢复的异常是通过KeeperException.ConnectionLossException来表示的,它意味着已经丢失了与ZooKeeper的连接。ZooKeeper会尝试重新连接,并且在大多数情况下重新连接会成功,并确保会话是完整的。
但是ZooKeeper不能判断与KeeperException.ConnectionLossException异常相关的操作是否成功执行。这种情况就是部分失败的一个例子。这时程序员有责任来解决这种不确定性,并且根据应用的情况来采取适当的操作。在这一点上,就需要对“幂等”(idempotent)操作和“非幂等”(Nonidempotent)操作进行区分。幂等操作是指那些一次或多次执行都会产生相同结果的操作,例如读请求或无条件执行的setData操作。对于幂等操作,只需要简单地进行重试即可。对于非幂等操作,就不能盲目地进行重试,因为它们多次执行的结果与一次执行是完全不同的。程序可以通过在znode的路径和它的数据中编码信息来检测是否非幂等操怍的更新已经完成。
③不可恢复的异常
在某些情况下,ZooKeeper会话会失效——也许因为超时或因为会话被关闭,两种情况下都会收到KeeperException.SessionExpiredException异常,或因为身份验证失败,KeeperException.AuthFailedException异常。无论上述哪种情况,所有与会话相关联的短暂znode都将丢失,因此应用程序需要在重新连接到ZooKeeper之前重建它的状态。
http://www.cnblogs.com/sunddenly/articles/4143859.html(讲解的比较好)
http://www.cnblogs.com/sunddenly/p/4138580.html
http://blog.csdn.net/jin5203344/article/details/53142027 (zab原子广播)
http://blog.csdn.net/pwlazy/article/details/8080626
http://www.cnblogs.com/sunddenly/p/4018459.html (比较全面的讲解)
http://www.cnblogs.com/sunddenly/p/4033574.html
http://blog.csdn.net/koflance/article/details/78598324
http://blog.csdn.net/a807557328/article/details/78016928 《zk的leader流程图》