一、ZooKeeper基本介绍
1.1、何为ZooKeeper
ZooKeeper是一个分布式协调服务的开源框架,核心功能是解决分布式集群中应用系统的一致性问题(超赞的功能)。
ZooKeeper的本质可以理解为一个分布式的小文件存储系统,结构类似于文件系统的目录树,在目录树节点进行数据存储、维护和管理,通过监控对这些数据状态的变化,从而实现基于数据的集群管理。
分布式系统:
分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。简单来说就是一群独立计算机集合共同对外提供服务,但是对于系统的用户来说,就像是一台计算机在提供服务一样。
分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。计算机越多,CPU、内存、存储资源等也就越多,能够处理的并发访问量也就越大。
互联网网站常用的架构:
1.2、ZooKeeper的优势
全局数据一致性:
ZK集群中每台服务器均会保存相同的一份数据副本,对于client来说,无论连接至哪台服务器,数据都是相同的;
集群中数据同步采用ZAB协议,即Zookeeper Atomic Broadcast(Zookeeper 原子广播协议):
可靠性:
ZK集群各服务器之间消息同步,只要有一台服务器接收消息成功,则ZK集群接收消息成功;
顺序性:
ZK集群中,消息存在先后顺序,具体又细分为全局有序和偏序两种;全局有序–指如果在一台服务器上消息a在消息b前发布,则在所有服务器上消息a都将在消息b前被发布;偏序–指如果消息b在消息a后被同一个发送者发布,a必将排在b前面;
数据更新原子性:
数据更新要么成功(半数以上节点成功),要么失败;
实时性:
client在一定时间范围内,获得服务器的更新信息。
1.3、ZooKeeper地位
大数据集群的心脏。
大数据生态里面,hadoop、hbase、hive…等组件都是分布式部署,这些组件利用Zookeeper的服务做了一些维持自身平衡的事情,比如集群管理、master选举、消息发布订阅、数据存储、分布式锁等。
分布式锁机制:
分布式锁的定义:在分布式系统中,应用可能部署在多台机器上,应用不在同一个jvm里面,这个时候还需要维护一个互斥排他的策略,需要一个跨jvm的锁同步,为了解决跨系统、跨jvm的锁,我们就必须引入分布式锁。
-
排他锁(写锁/独占锁)
核心:保证当前有且仅有一个事务获得锁,并且锁释放之后,所有正在等待获取锁的事务都能够被通知到;
保证在分布式高并发情况下节点的创建一定能够保证全局唯一性(全局数据一致性) -
共享锁(读锁)
加了共享锁之后,数据对象对所有事务都可见;
如果事务T1对数据对象O1加上了共享锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个数据对象加共享锁,直到该数据对象上的所有共享锁都被释放。
二、ZooKeeper集群
Zookeeper集群通常由2n+1台servers组成。这是因为为了保证Leader选举(基于Paxos算法的实现)能够得到多数的支持,所以ZooKeeper集群的数量一般为奇数。超过半数有效。
2.1、ZooKeeper集群介绍
ZK集群图示:
2.2、集群角色对比:
ZK集群假设有100台服务器,可设定Leader 1台,Follower 4台,Observer 95台。
角色对比 | 节点名称 | 事务请求(写操作) | 非事务请求(读操作) | Leader选举投票 | 是否必须存在 |
---|---|---|---|---|---|
Leader | 主节点 | 唯一可处理,保证顺序性,调度集群服务器 | 不处理 | 参与 | 是 |
Follower | 从节点 | 转发事务请求给Leader | 处理非事务(读操作)请求 | 参与 | 是 |
Observer | 观察者 | 转发事务请求给Leader | 处理非事务(读操作)请求 | 不参与 | 针对访问量比较大的zookeeper集群,负责观察Zookeeper集群的最新状态变化并将这些状态同步过来,通常用于提升集群的非事务处理能力 |
Server:服务器,所有的节点都是一台服务器;
Client:客户端;
事务:
一个对于写操作(create,setData,delete等)的请求,统一转给Leader处理,并由其决定编号、执行操作的过程;
事务型请求只能有一个,保证数据的一致性。
2.3、Master的选举
很多应用都是master-slave架构,master必须7*24小时工作,但是每次只能一个master在工作,这时需要一个选举机制,确定一个active状态的master,当active的master出现故障挂掉的时候,standby的master顶上去,这里主要讲zk这端的实现。
Master选举的功能:
各个master注册到zk的目录下,创建临时节点,成功在zk创建临时节点的目录,也就被选举为Master,其它备用的Master就会收到监听zk里面临时节点的变化,一旦删除,就会争夺创建临时节点的权利成为新的Master。
本质其实是利用zookeeper的临时节点的特性:临时节点随着会话的消亡而消亡,同一个临时节点只能创建一个,创建失败的节点(从master)对创建成功节点(主master)进行监控,一旦创建成功的节点(主master)会话消失,之前创建失败的节点(从master)就会监听到去抢夺创建临时节点
三、ZooKeeper集群选举机制
zookeeper集群选举默认的算法是FastLeaderElection,采用投票数大于半数则胜出的逻辑。
3.1、概述
服务器ID:
每台服务器都有编号,编号越大在选择算法中的权重越大。
选举状态:
状态 | 描述 |
---|---|
LOOKING | 竞选状态,很短暂 |
LEADING | 领导者状态 |
FOLLOWING | 随从状态,同步leader状态,参与投票 |
OBSERVING | 观察状态,同步leader状态,不参与投票 |
数据ID/事务id:
- 服务器中存放的最新数据version;
- 值越大说明数据越新,在选举算法中数据越新权重越大。
逻辑时钟:
- 也叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的;
- 每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。
3.2、全新集群选举流程
以5台服务器为例,每台服务器均没有数据,编号为1、2、3、4、5,按编号依次启动,选举过程如下:
-
服务器1启动,给自己投票,然后发投票信息,由于其它机器还未启动所以它收不到反馈信息,服务器1的状态为LOOKING ;
-
服务器2启动,给自己投票,同时与服务器1交换投票信息结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以服务器1、2的状态依然是LOOKING;
-
服务器3启动,给自己投票,同时与服务器1、2交换投票信息结果,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为Leader,服务器1,2成为Follower ;
-
服务器4启动,给自己投票,同时与服务器1、2、3交换投票信息结果,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为Follower ;
-
服务器5启动,后面的逻辑同服务器4成为Follower 。
3.3、非全新集群选举
正常运行的zookeeper集群,中途会存在有机器down掉的情况,在需要重新选举时,选举过程就需要加入事务ID、服务器ID和逻辑时钟。
- 事务ID(zxid):即数据ID,数据越新,version就大,数据每次更新都会更新version。
- 服务器ID:机器编号,就是我们配置的myid中的值,每个机器一个。
- 逻辑时钟:这个值从0开始递增,每次选举对应一个值。 如果在同一次选举中,这个值是一致的。
Leader选举标准:
- 逻辑时钟小的选举结果被忽略,重新投票;
- 统一逻辑时钟后,事务ID大的胜出;
- 事务ID相同的情况下,服务器ID大的胜出;
四、ZooKeeper数据模型
ZooKeeper的数据模型,在结构上和标准文件系统相似:拥有一个层次的命名空间;采用树形层次结构。
4.1、数据结构
图中ZooKeeper树的每个节点称为一个Znode, 每个Znode由3部分组成:
- stat:此为状态信息, 描述该Znode的版本, 权限等信息
- data:与该Znode关联的数据
- children:该Znode下的子节点
Znode特性:
Znode特性 | 描述 |
---|---|
Znode兼具文件和目录两种特点 | 可以像文件一样维护数据、元信息、ACL、时间戳等数据结构,又可以像目录一样可以作为路径标识的一部分;用户对Znode具有增、删、改、查等操作(权限允许的情况下)。 |
Znode具有原子性操作 | 读操作将获取与节点相关的所有数据,写操作将替换掉节点的所有数据;每个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,限定了特定用户对目标节点可以执行的操作。 |
Znode存储数据大小有限制 | ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储;它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等;这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位;ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但是常规使用中应该远小于此值。 |
Znode通过路径引用 | 如同Unix中的文件路径,路径要求是绝对的、唯一的,必须由斜杠字符来开头,路径不能改变;在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制;字符串"/zookeeper"用以保存管理信息,比如关键配额信息。 |
4.2、zookeeper的文件系统
zk的所有Znode不管父子节点都能带数据,但linux的目录不能,所以zk里面的路径不能叫文件夹也不能叫文件,统一称为Znode。
zookeeper的文件系统的特点:
zk的文件系统和Linux的文件系统目录结构一样,从/开始;
zk的访问路径只有绝对路径,没有相对路径;
zk中没有文件和目录的概念,只有znode节点,Znode既有文件的功能,又有目录的功能。
4.3、节点类型
Znode节点类型可分为两种:临时节点和永久节点。ZK的数据类型类似一棵树,所有的节点都称为Znode,节点的类型在创建时被确定,不能改变。
临时节点:
临时节点的生命周期依赖于创建它们的会话;
一旦会话结束,临时节点将被自动删除,也可以手动删除;
临时节点不允许拥有子节点。
永久节点:
永久节点的生命周期不依赖于会话,只有在客户端显示执行删除操作的时候,才能被删除。
序列化特性:
Znode节点有序性,Znode节点创建时,若指定序列化特性,该Znode的名字后面会自动追加一个不断增加的序列号;
序列号对于此节点的父节点来说是唯一的,这样便会记录每个子节点创建的先后顺序,它的格式为“%10d”(10位数字,没有数值的数位用0补充,例如“0000000001”)。
序列化特性下的四种Znode节点类型:
- PERSISTENT:永久节点
- EPHEMERAL:临时节点
- PERSISTENT_SEQUENTIAL:永久节点、序列化
- EPHEMERAL_SEQUENTIAL:临时节点、序列化
4.4、节点属性
znode包含了一系列的属性,通过命令get,可以获得节点的属性:
属性介绍:
属性 | 描述 |
---|---|
cZxid | Znode创建的事务id |
ctime | 节点创建时的时间戳 |
mZxid | Znode被修改的事务id,即每次对znode的修改都会更新mZxid。 |
mtime | 节点最新一次更新发生时的时间戳 |
pzxid | 事务id,增删改的序号 |
cversion | 子节点的版本号。当znode的子节点有变化时,cversion 的值就会增加1。 |
dataVersion | 数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据),有效避免了数据更新时出现的先后顺序问题。 |
aclVersion | 表示对此znode的acl版本 |
ephemeralOwner | |
dataLength | znode数据字段的长度 |
事务id(zxid):
对于zk来说,每次的变化都会产生一个唯一的事务id,zxid(ZooKeeper Transaction Id)。通过zxid,可以确定更新操作的先后顺序。例如,如果zxid1小于zxid2,说明zxid1操作先于zxid2发生,zxid对于整个zk都是唯一的,即使操作的是不同的znode。
4.5、节点的加入和退出
首先,在zk中创建持久节点 /GroupMembers 作为父节点,父节点监听子节点的变化,client通过注册到zk,会在/GroupMembers下创建临时节点,临时节点的特性时当客户端与zk断开连接时会自动删除,不论是创建和删除,zk server都会监听,通过Watcher监听与通知机制,并且会把变动的结果通知到到其它client,这样,其它所有client都知道了其它兄弟们的存活情况。
#连接客户端
zkCli.sh -server node01
#命令提示
help
create [-s][-e] path data acl
# -s 顺序节点
# -e 临时节点,若不指定,则表示持久节点
# acl用来进行权限控制。
#永久节点需要显示的删除:
delete
rmr
#临时节点可显示删除,也可断开时自动消失
节点的类型一共以四种
临时
永久
有序的临时节点
有序的永久节点
#创建顺序节点:
create -s /test 123
#创建永久节点:
create /test-p 123p
#读取节点
#路径下的子节点列表:ls path [watch]
ls /
#获取节点信息:get path [watch]
get /test
#获取路径节点信息和路径下子节点列表 ls2 path [watch]
ls2 /test
#更新节点:set path data [version]
#data就是要更新的新内容,version表示数据版本。
set /test abc
#删除节点
#delete path [version]
#若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点。
delete /test
#rmr path
#可以递归删除节点。
rmr /test
#quota
#setquota -n|-b val path 对节点增加限制。
# n:表示子节点的最大个数
# b:表示数据值的最大长度
# val:子节点最大个数或数据值的最大长度
# path:节点路径
setquota -n 2 /quota #设定test下只能有一个子节点
setquota -b 20 /quota #设定test节点只能存放20b数据
listquota path #列出指定节点的quota
listquota /quota
delquota [-n|-b] path #删除quota
delquota -n /quota
delquota -b /quota
history #列出命令历史
redo #该命令可以重新执行指定命令编号的历史命令,命令编号可以通过history查看
redo 11
4.6、权限控制ACL
zookeeper有ACL( Access Control List )权限控制,可以控制节点的读写操作,保证数据的安全性。
ACL权限设置三部分组成,分别是权限模式、授权对象、权限信息。
权限设置:setAcl
权限查看:getAcl
权限模式:
zookeeper服务器进行权限验证的方式,比如手机的指纹解锁、密码解锁。
权限模式分为两类:
- 范围验证: 范围就是zookeeper可以针对一个ip或者一段ip地址授予权限,相当于手机的指纹解锁;
- 口令验证: 可以理解为用户名密码的方式,相当于手机的密码解锁,知道了用户名密码后所有的人都相当于授予了权限。
授权对象:
授权对象就是给用户授予权限,如果是范围验证,那么授权对象就是ip地址,如果是口令验证,授权对象就是用户名。
授权信息:
授权信息就是指用户具体有什么权力,比如我们手机解锁成功后,可以选择打电话、发微信或者上网查资料。
4.7、数据的持久化
zookeeper的数据存储在内存中,数据的持久化有记录事务日志和快照两种方式。
记录事务日志:
在配置文件zoo.cfg中,利用dataDir来指定事务日志存放位置。
随着磁盘不断进行IO操作,事务日志也会不断增多,占用的磁盘空间会不断增加,为避免磁盘空间的占用影响系统性能,可以通过参数zookeeper.preAllocSize来对磁盘进行设置。
五、ZooKeeper Watcher机制
ZooKeeper中引入了Watcher机制的概念,实现了分布式数据发布/订阅功能,定义了一种一对多的订阅关系,能让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使他们能够做出相应的处理。
5.1、Watcher机制
Watcher机制流程:
- 客户端向服务端注册一个Watcher监听;
- 服务端的一些事件触发Watcher监听;
- 向指定客户端发送一个事件通知。
Watcher机制特点:
特点 | 描述 |
---|---|
事件封装 | ZooKeeper使用WatchedEvent对象来封装服务端事件并进行传递 |
事件属性 | 通知状态(keeperState);事件类型(EventType);节点路径(path) |
先注册再触发 | Watcher机制,必须客户端先去服务端注册监听,事件发送才会触发监听,通知给客户端 |
一次性触发 | 事件发生触发监听,一个watcher event就会被发送到设置监听的客户端,这种效果是一次性的,后续再次发生同样的事件,不会再次触发 |
event异步发送 | watcher的通知事件从服务端发送到客户端是异步的 |
触发event种类 | 节点创建,节点删除,节点改变,子节点改变等 |
5.2、通知状态和事件类型
同一个事件类型在不同的通知状态中代表的含义有所不同:
Keeper State | EventType | 触发条件 | 说明 |
---|---|---|---|
None(-1) | 客户端与Zookeeper服务端建立连结成功 | ||
Disconnected(0)) | None(-1) | 客户端与Zookeeper服务器断开连结 | |
AuthFailed(4)) | None(-1) | 通常有2种情况:1.使用错误的schema进行权限检查;2.SASL权限检查失败 | 同时也会收到AuthFailedException异常 |
Expired(-112)) | Node(-1) | 会话超时 | 客户端会话失效,通常同时会收到SessionExpiredException异常 |
SyncConnected(0) | NodeCreated(1) | Watcher监听的对应数据节点被创建 | |
NodeDeleted(2) | Watcher监听的对应数据节点被删除 | 此时客户端与服务端处于连结状态 | |
NodeDataChanged(3) | Watcher监听的对应数据节点的数据内容发生变更 | ||
NodeChildChanged(4) | Watcher监听的对应数据节点的子节点列表发生变更 |
5.3、用途
master选举的Znode监听:
当备用的master发现Znode已经被其它master创建后,这时备用master会注册监听这个Znode的变化。
锁机制:
基于监听机制上才能实现,比如释放锁的时候,需要告诉其它访问的应用这个Znode代表的锁已经释放,通知其它应用可以获取锁以进行下一步操作。