一、Zookeeper是什么
- Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的框架;
- Zookeeper从设计模式的角度理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接收观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经注册的那些观察者做出相应的反应。
- Zookeeper = 文件系统 + 通知机制
二、Zookeeper特点
- Zookeeper是由一个leader和多个follower组成的集群;
- 集群中只要有半数以上的节点存活,Zookeeper集群就能正常服务;
- 全局数据一致性:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的;
- 数据读取/更新原子性:客户端读取数据,只可能全部读取,不会发生部分读取的情况;更新数据要么成功,要么失败;
- 实时性:在一定的时间范围内,Client能读到最新数据。
三、Zookeeper服务
3.1 数据模型
1. 概述:
Zookeeper维护着一个树形层次结构,树中的节点被称为znode。znode既可以是文件夹,也可以存储具体的数据,并且有一个与之相关联的ACL。Zookeeper被设计用来实现协调服务(这类服务通常使用小数据文件),而不是用于大容量数据存储,因此一个znode能存储的数据被限制在1MB以内。
2. ACL:Access Control List 权限控制列表
每一个znode创建时都会带有一个ACL列表,用于决定谁可以对它执行何种操作。
ACL使用 scheme🆔perm 来标识,主要涵盖3个方面:
- 权限模式(Scheme):授权的策略
- 授权对象(ID):授权的对象
- 权限(Permisssion):授予的权限
Scheme:
world:默认方式,相当于全部都能访问
auth:代表已经认证通过的用户
digest:用户名:密码这种方式来识别客户端
ip:使用客户端的 IP 地址来识别客户端
sasl:通过 Keberos 来识别客户端
ID:权限赋予一个用户或者一个实体,例如:IP地址或者机器。
permission:授予什么权限,包括CREATE、READ、WRITE、DELETE、ADMIN,也就是增、删、改、查、管理权限(管理就是可以设置节点的ACL)
3. 短暂znode和持久znode:
短暂znode:
- 创建znode的客户端断开连接时,短暂znode都会被删除。
- 短暂znode不可以有子节点
- 作用:可以提供分布式锁服务
持久znode:
- 持久znode不会因为客户端断开连接而被删除,只有当客户端明确指明要删除时才会删除
4. 顺序号:
可以在创建znode的时候加-s参数来实现自增的顺序号
**作用:**在一个分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端就可以通过顺序号来推断事件的顺序。
3.2 实现
1. 两种运行机制
- 独立模式:即只有一个Zookeeper服务器,适用于测试环境,但不能保证高可用性和可恢复性;
- 复制模式:Zookeeper通常以复制模式运行于一个计算机集群上,这个计算机集群被称为一个集合体。只要集合体中半数以上的机器处于可用状态,它就能提供服务。
2. 半数机制
只要集合体中半数以上的机器处于可用状态,它就能提供服务。
Zookeeper集群一般是奇数台,因为在一个有5个节点的集合体中,最多可容忍2台节点出现故障,而在一个有6台节点的集合体中,也最多容忍2台节点出现故障。
3. Leader选举
首先说明两个字段的含义:myid:zookeeper所在机器配置的id,ZXID (ZooKeeper Transaction ID):致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。
两种情况(以三台节点举例):
(1)服务器初始化启动时选举
-
每个Server发出一个投票。 每一个Server都会将自己作为Leader服务器来进行投票,将(myid, ZXID)发送给其他Server,在本例中Server1的投票是(1, 0),Server2的投票是(2,0),它们各自将投票发个对方;
-
接收来自各个服务器的投票。集群的每个服务器收到投票后,首先判断改投票的有效性,如检验是否是本轮投票;
-
处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票PK,PK规则如下:
- 优先检查ZXID。ZXID比较大的胜出;
- 如果ZXID相同,那么就比较myid。myid大的胜出
对于Server1而言,它的投票是(1,0),接收Server2的投票时(2,0),因为此时二者的ZXID相同,而Server2的myid更大,所以Server1更新自己的投票为(2,0),然后重新投票;对于Server2而言,无需更新自己的投票,只需把之前的投票信息再次向集群中发送即可;
-
统计投票。每次投票后,服务器都会统计投票信息,判断是否有过半机器接收到相同的投票信息,如果有,便选出Leader;
-
改变服务器的状态。一旦确定了Leader,每个服务器就会更新自己的状态,如果是Follower,那么就变更为FOLLOWING,如果是Leader,就变更为LEADING。
(2)服务器运行期间选举
- 变更状态。Leader挂后,余下的非Observer服务器都会将自己的服务器状态变为LOOKING,然后开始进入Leader选举过程;
- 每个Server会发出一个投票。在运行期间,每个服务器上的ZXID可能不同,此时假定Server1的ZXID为123,Server3的ZXID为122;在第一轮投票中,Server1和Server3都会投自己,产生投票(1,123),(3,122),然后各自将投票发送给集群中所有的机器。
- 接收来自各个服务器的投票。与启动过程相同。
- 处理投票。与启动过程相同。
- 统计投票。与启动过程相同。
- 改变服务器的状态。与启动过程相同。
四、Zookeeper的作用
4.1 统一命名服务
在分布式环境下,经常需要堆应用/服务进行统一命名,便于识别。
例如:IP不容易记住,而域名容易记住。
4.2 统一配置管理
-
背景:在分布式环境下,配置文件同步非常常见,一般要求一个集群中,所有节点的配置信息都是一致的,对配置文件修改后,希望能快速同步到各个节点上。
-
实现:
1)将配置信息写入Zookeeper的一个Znode
2)各个客户端监听这个Znode
3)一旦Znode中的数据被修改,Zookeeper将通知各个客户端服务器
4.3 统一集群管理
-
背景:在分布式环境中,实时掌握每个节点的状态,根据节点的实时状态做出调整
-
实现:
1)将节点信息写入Zookeeper的一个Znode
2)监听这个Znode可获取它的实时状态变化
4.4 服务器动态上下线
4.5 软负载均衡
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求
五、监听器原理
-
创建main线程;
-
启动Zookeeper客户端,此时会创建两个线程,一个负责连接通信(connect),一个负责监听(listener);
-
通过connect线程将注册的监听事件发送给Zookeeper;
-
在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中;
-
Zookeeper监听到有数据或路径变化,就将这个消息发送给listener线程;
-
listener线程内部调用process()方法