Zookeeper概述
1.ZooKeeper最为主要的使⽤场景,是作为分布式系统的分布式协同服务。
2.分布式系统中每台服务器的算力和资源都是有限的,但是我们通过分布式系统组成集群
就可以对算力和资源进行无限扩张,但是分布式节点间的协调就成了问题。
3.就像我们的开发团队之间的协作一样,我们需要同步任务情况,leader也需要对我们的
工作进度需要了解,然后根据情况进行协调。
4.分布式系统的协调工作就是通过某种方式,让每个节点的信息能够同步和共享。这依赖于服务进程之间
的通信。通信方式有两种:
(1)通过网络进行信息共享:就好像开发leader把任务传达下去,组员通过听leader命令
或者看leader的邮件知道自己要干什么。
(2)通过共享存储:好比开发leader按照约定的时间和路径,把任务分配表放到了svn上,
组员每天去svn上拉取最新的任务分配表,然后执行。
5.ZooKeeper对分布式系统的协调,使用的是共享存储。但分布式应用也需要和存储进行网络通信。
6.ZooKeeper就像是svn,存储了任务的分配、完成情况等共享信息。
(1)每个分布式应用的节点就是组员,订阅这些共享信息。
(2)当主节点(组leader),对某个从节点的分工信息作出改变时,相关订阅的从节点
得到zookeeper的通知,取得⾃⼰最新的任务分配。
(3)完成工作后,把完成情况存储到zookeeper。
(4)主节点订阅了该任务的完成情况信息,所以将得到zookeeper的完⼯的通知。
7.zookeeper是个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如:
数据订阅/发布、负载均衡、命名服务、集群管理、分布式锁和分布式队列等功能。
小结:大多数分布式系统中的问题,都源于信息的共享出了问题。如果各个节点间信息不能及时共享和同
步,那么就会在协作过程中产生各种问题。ZooKeeper解决协同问题的关键,就是在于保证分布式
系统信息的一致性。
集群角色
1.通常下分布式系统下的集群每一台服务器都有自己的角色,比如比较经典的主从模式,有master节点处理
写请求并同步数据,有slave节点负责对请求及数据备份。
2.zookeeper中并没有沿用主从模式,而是采用leader,Follower,ObServer三种角色。
(1)过Leader选举来选定⼀台被称为Leader的机器。该节点可以负责读写请求。
(2)Follower节点可以接收客户端的读请求和参与投票。
(3)Observer节点也是接收客户端的读请求,但是不参与投票。
会话(session)
1.Session指客户端会话,一个客户端连接是指客户端和服务端之间的一个TCP长连接,
2.Zookeeper对外的服务端口默认为2181,客户端启动的时候,首先会与服务器建建立TCP连接,
从第1次连接建立开始,客户端会话的生命周期也开始了。
3.通过这个连接,客户端能够心跳检测与服务器保持有效的会话,也能够向Zookeeper服务器
发送请求并接受响应,同时还能够通过该连接接受来自服务器的Watch事件通知。
数据节点(Znode)
- 通常我们说的节点指的是集群中某一台服务器的节点,然而zookeeper中有两种节点:
第一种同指服务器节点,也就是机器节点。第二种则是指的数据单元,也就是数据节点(ZNode)。
以文件结构也可以说是树状结构去存储数据节点。
版本
- Zookeeper的每个Znode上都会存储数据,对于每个ZNode,Zookeeper都会为其维护
一个叫作Stat的数据结构,Stat记录了这个ZNode的三个数据版本,分别是
version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)、aversion(当前ZNode的ACL版本)。
Watcher(事件监听器)
- Wathcer(事件监听器),是Zookeeper中很重要的特性,Zookeeper允许用户在指定节点上注册
Watcher,并且在某些特定事件触发的时候,Zookeeper服务端会将事件通知到感兴趣的客户端,
该机制是Zookeeper实现分布式协调服务的重要特性。 - 我们客户端与服务端产生会话后,会在客户端维护一个WatcherManage对象,当有事件被触发的时候
服务端会基于之前创建的TCP长连接进行通知,也就是回调我们实现Watcher接口下的process方法。
ACL
Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,其定义了如下五种权限:
· CREATE:创建子节点的权限。
· READ:获取节点数据和子节点列表的权限。
· WRITE:更新节点数据的权限。
· DELETE:删除子节点的权限。
· ADMIN:设置节点ACL的权限。
ZooKeeper数据模型Znode
1.zookeeper是以文件结构为数据存储模型的,Znode是zookeeper中的最小数据单位。
2.就像我们的文件目录一样,以树状的形式分层存储数据。
3.Zookeeper的节点类型大致可以分为3种:持久性节点,临时性节点,顺序性节点。
可以具体划分为:持久节点、持久顺序节点、临时节点、临时顺序节点。
不同类型的节点则会有不同的生命周期。
4.持久节点:指节点被创建后会一直存在服务器,直到删除操作主动清除。
5.持久顺序节点:就是有顺序的持久节点,会在节点名后加上数字后缀,来表示其顺序。
6.临时节点:它的生命周期和客户端会话绑定,客户端会话结束,节点会被删除掉,
临时节点不能创建子节点。
7.临时顺序节点:就是有顺序的临时节点,在其创建的时候会在名字后加上数字后缀。
ZNode信息
1.Znode的节点信息包含2部分:节点数据内容和节点状态信息;
2.数据内容(quota)也就是我们创建节点的时候上传的数据。
3.状态信息包括: cZxid (节点创建事务ID)、ctime(节点创建时间)、mZxid(最后一次修改事务ID)、
mtime(最后一次修改时间)、pZxid(子节点列表变更事务ID)、cversion(子节点版本号)、
dataVersion(内容版本号)、aclVersion(acl版本)、 ephemeralOwner(临时节点时的会话sessionID,持久性节点那么值为0)
dataLength(表示数据长度)、numChildren (直系子节点数)。
Watcher(变更通知)
- ZooKeeper中引入了Watcher机制来实现分布式通知功能。ZooKeeper允许客户端向服务
端注册多个Watcher监听,当服务端的那些指定事件触发了这个Watcher,那么就会向指定客户端发
送一个事件通知来实现分布式的通知功能。 - Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。
流程为:客户端在向Zookeeper服务器注册事件时会将Watcher对象存储在客户端的
WatcherManager当中。当服务器触发了注册事件后,会向客户端发送通知,客户端线程
从WatcherManager中取出对应的Watcher对象来执行回调逻辑。
ACL机制(保障数据的安全)
1.权限模式(Scheme):
(1)IP:IP模式就是通过IP地址粒度来进行权限控制,或者一个网段。
(2)Digest:以"username:password"形式的权限标识来进行权限配置,便于区分不同应用来进行权限控制。
(3)World:数据权限对所有用户开放,即所有用户都可以操作ZooKeeper上的数据。
(4)Super:Super模式,顾名思义就是超级用户的意思,也是种特殊的Digest模式。
2.授权对象(ID):
(1)IP:通常是个IP地址或IP段。
(2)Digest:具体分配指定的用户。
(3)World:只有1个ID :anyone(所有用户)。
(4)Super:超级用户。
3.权限(Permission):
(1)CREATE(C):数据节点的创建权限,包括子节点。
(2)DELETE(D):节点和子节点的删除权限。
(3)READ(R):数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或子节点列表。
(4)WRITE(W):数据节点的更新权限,允许授权对象对该数据节点进行更新操作。
(5)ADMIN(A):数据节点的管理权限,允许授权对象对该数据节点进行 ACL 相关的设置操作。
ZooKeeper命令操作
1.连接本地的zookeeper服务器:./zkcli.sh 或者 连接指定的服务器:./zkCli.sh -server ip:port
2.创建节点: create [-s][-e] path data acl(-s或-e分别指定节点特性,顺序或临时节点,
若不指定,则创建持久节点;acl进行权限控制)
3.创建顺序节点:create -s /zk 123。
4.创建临时节点:使用 create -e /zk-temp 123 命令创建zk-temp临时节点。
5.创建永久节点:create /zk-permanent 123。
6.读取节点:有ls 命令和get 命令:
(1)ls path:可以列出Zookeeper指定节点下的所有子节点。
(2)get path:可以获取Zookeeper指定节点的数据内容和属性信息。
7.更新节点:set path data [version] data就是要更新的新内容,version表示数据版本。
8.删除节点:delete path [version]
数据发布/订阅
1.有两种模式:推/拉数据,推模式的话是由服务端主动将数据推送到客户端那边。
拉模式的话是基于通知机制或者定时拉取。
2.ZooKeeper 采用推拉相结合方式:客户端向服务端注册需要关注的事件,事件触发的
时候服务端通过watcher机制通知客户端,客户端再进行数据重新获取。
3.需要注意的是watcher是一次性通知的,如果需要持续监听则需要重复注册。
命名服务
- 在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等——这些
我们都可以统称它们为名字(Name),其中较为常见的一些分布式服务框架(如RPC、RMI)中
的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提
供者的信息等。 - ZooKeeper 提供的命名服务功能能够帮助应用系统通过1个资源引用的方式来实现对资源的定位与使
用。另外,广义上命名服务的资源定位都不是真正意义的实体资源——在分布式环境中,上层应用仅仅
需要1个全局唯一的名字,类似于数据库中的唯一主键。
集群管理
1.有集群监控与集群控制两大块,前者侧重对集群运行时状态的收集,后者则是对集群进行操作与控制。
2.实现步骤:
(1)注册收集器机器:创建收集器根节点,收集器机器启动的时候会在收集器节点下创建对应节点。
(2)任务分发:根据收集器子节点的个数对日志源机器进行分组,然后将日志源机器列表写入到收集
器的子节点中。每个收集器机器都能够从对应的收集器节点上获取日志源机器列表,开始日志收集工作。
(3)状态汇报:考虑到收集器机器的宕机风险,需要一个收集器的状态汇报机制。
每个收集器机器都需要定期向该节点写入自己的状态信息。我们可以把这种策略看作是心跳检测机制,
通常收集器机器都会在这个节点中写入日志收集进度信息。日志系统根据该状态子节点的最后更新时
间来判断对应的收集器机器是否存活。
(4)动态分配:如果收集器机器挂掉或是扩容了,就需要动态地进行收集任务的分配。
在运行过程中,日志系统始终关注收集器子节点下所有子节点的变更,一旦检测到有
收集器机器停止汇报或是有新的收集器机器加入,就要开始进行任务的重新分配。
无论是针对收集器机器停止汇报还是新机器加入的情况,日志系统都需要将之前分配
给该收集器的所有任务进行转移。
Master选举
1.在分布式系统,往往需要在这些分布在不同机器上的独立系统单元中选出一个所谓的“协调者”,
在计算机中,我们称之为Master。
2.Master是用来协调集群中的系统单元,具有分布式系统状态变更的权力。比如:在读写分离场景中,
往往是由master节点进行写请求处理并同步给其他子节点。
3.利用多个客户端请求创建同个节点,最终只有一个客户端能够创建成功的特性,就能
很容易地在分布式环境中进⾏Master选举了。
4.其他没有注册的客户端可以注册节点变更的Watcher,用于监控当前的Master机器是
否存活,一旦发现当前的Master挂了,那么其余的客户端将会重新进行Master选举。
分布式锁
1.分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
2.可以依赖于关系型数据库固有的排他性来实现不同进程之间的互斥。但是这种方式不推荐,
因为绝大多数的分布式系统的瓶颈都在数据库上,所以一般不会让数据库有额外的操作。
3.我们可以使用ZooKeeper实现分布式锁,主要有两种实现方式:排他锁和共享锁两类分布式锁。
4.排他锁:简称 X 锁,又称写锁或独占锁,我们要保证如何当前有且仅有1个事务获得锁,
并且锁被释放后,所有正在等待获取锁的事务都能够被通知到:
(1)定义锁:创建一个lock节点,在这个节点下创建一个节点来表示一个锁。
(2)其他事务如果需要获取锁则需要在这个节点下创建相同的lock锁,如果失败则对
该节点注册事件通知。
(3)释放锁:在另一个客户端宕机或者手动删除该节点的时候都可以释放锁。
5.共享锁:简称S锁,又称为读锁,可以实现读读不互斥和读写互斥:
(1)当T1这个事务对资源加上共享锁后,之后的事务只能对其进行读取操作,其他事务也
只能进行加锁,直到所有的共享锁都释放。
(2)共享锁和排他锁最根本的区别在于,加上排他锁后,数据对象只对1个事务可见,而加上共享锁后,
数据对所有事务都可见。
(3)我们同样是以节点的方式来定义一个锁,不过要在节点加上读(W)/写(R)的标识是读请求还是写请求。
(4)当获取锁时则需要判断节点的顺序,我们只要在加入节点的时候并对前一个节点(锁)注册一个事情,
在当前事务之前的节点发生变化的时候可以及时做出通知。
(5)释放锁:释放锁的流程与独占锁一致。
分布式队列
1.分为两类:1种是常规的FIFO先进先出队列模型,还有1种是 等待队列元素聚
集后统一安排处理执行的Barrier模型。
2.FIFO先进先出:其实现方式与共享锁的实现非常相似,都是订阅前一个节点,然后进行事件Watcher通知。
3.Barrier原意是指障碍物、屏障,而在分布式系统中,特指系统之间的一个协调条件,规定了一个队列的
元素必须都集聚后才能统一进行安排,否则一直等待。
(1)这往往出现在那些大规模分布式并行计算的应用场景上:最终的合并计算需要基于很多并行计算
的子结果来进行。
(2)在 FIFO 队列的基础上进行了增强,创建一个/queue_barrier节点在将其数据内容设置一个barrier值。
例如:barrier=10, 表示只有当节点个数达到10后,才会打开Barrier。
(3)监听/queue_barrier节点下的字节点,收到通知后获取barrier查看是否等于10.
ZAB协议
- ZAB协议并不像Paxos算法那样 是种通用的分布式一致性算法,它是种特别为zookeeper专门设计
的一种支持崩溃恢复的原子广播协议。
基于该协议,Zookeeper实现了一种主备模式的系统架构来保持集群中各副本之间的数据的一致性,
使用一个单一的进行来接收客户端的请求通过ZAB的广播协议同步到所有的follower副本中,ZAB协议的
主备模型保证了集群中只有一个leader节点进行消息广播。
所以可以好地处理客户端大量的并发请求。考虑到主进程在任何时候都有可能出现崩溃退出或重启现象,
因此,ZAB协议还需要做到当前主进程当出现上述异常情况的时候可以正常工作。
ZAB崩溃恢复模式:
1.进行奔溃模式的前提是:leader节点出现了宕机或者心跳断开的情况。这种情况下就需要重新进行leader
选举了,选举出leader节点,当集群种大半的follower节点与leader节点完成状态同步后则退出该模式。
2.状态同步指的是数据同步,保证集群中过半的机器能够和Leader服务器的数据状态保持一致。
3.如果在崩溃恢复过程中出现一个需要被丢弃的提案,那么在崩溃恢复结束后需要跳过该事务Proposal(事务)。
4.Leader选举算法能够保证新选举出来的Leader服务器拥有集群中所有机器最大编号(ZXID)的事务Proposal,
那么就可以保证这个新选举出来的Leader一定具有所有已经提交的提案。
5.Leader节点会先确认事务日志中的所有Proposal是否都已经被集群中过半的机器提交了,
是否完成数据同步。
消息广播模式
1.当完全了leader选举并状态同步完成后,只要有加入该集群的follower节点那么就会自动进行数据恢复模式,
与主节点完成数据同步,并参与消息广播的流程中。
2.在集群中只有leader节点才有事务处理权限,当leader节点收到事务请求后会发起一轮消息广播。
3.如果是非leader节点收到事务请求,则会转发给leader节点。
4.ZAB协议中的消息广播使用的是原子广播协议,类似于二阶段提交协议。针对客户端的事务请求,leader
节点会产生一个事务(proposal)然后将其广播给所有的follower节点,并收集选票,但得到半数以上
回应的时候就会提出Commit提交事务,而不需要全部的follower节点都响应。
5.采用了崩溃恢复模式来解决Leader服务器崩溃退出带来的数据不一致问题。
6.整个消息广播协议是基于具有FIFO特性的TCP协议来进行网络通信的,因此能够很容易保证消息
广播过程中消息接受与发送的顺序性。
7.leader节点发送proposal事务时会分配一个事务ID(ZXID),因为要保证每个消息的因果关系,
因此要将每一个事务通过ZXID的顺序来进行排序和处理。
运行时状态分析
1.在ZAB协议的设计中,每个进程都有可能处于如下三种状态:
(1)LOOKING:Leader选举阶段。
(2)FOLLOWING:Follower服务器和Leader服务器保持同步状态。
(3)LEADING:Leader服务器作为主进程领导状态。
2.所有进程初始状态都是LOOKING状态,此时不存在Leader,进程会试图选举出新的Leader。
3.如果发现已经选举出新的Leader了,那么就会切换到FOLLOWING状态,并开始和Leader保持同步。
4.一个Follower只能和一个Leader保持同步,Leader进程和所有的Follower进程之间都通过心跳检测
机制来感知彼此的情况。
5.在指定时间内Leader无法从过半的Follower进程那接收到心跳检测,或者TCP连接断开,
那么Leader会放弃当前周期的领导,并转换到LOOKING状态,其他的Follower也会选择
放弃这个Leader,同时转换到LOOKING状态,之后会进行新一轮的Leader选举。