ZooKeeper基础总结

ZooKeeper基础总结

结合了Guide哥和Hollis哥的文章总结学习,方便后续复习整理。

[TOC]

1.ZooKeeper介绍

1.1ZooKeeper概览

ZooKeeper是一个开源的分布式协调服务,它的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

ZooKeeper为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。这些功能的实现主要依赖于ZooKeeper提供的数据存储+事件监听功能。

ZooKeeper将数据保存在内存中,性能是不错的。在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景)。

1.2ZooKeeper特点

  • 顺序一致性:从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到ZooKeeper中去。

  • 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。

  • 单一系统映像:无论客户端连到哪一个ZooKeeper服务器上,其看到的服务端数据模型都是一致的。

  • 可靠性:一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。

  • 实时性:每个客户端的系统视图都是最新的。

1.3ZooKeeper应用场景

  1. 分布式配置管理:ZooKeeper可以存储配置信息,应用程序可以动态读取配置信息。
  2. 分布式同步:ZooKeeper可以协调各个节点的同步,确保数据的一致性。
  3. 命名服务:ZooKeeper可以作为一个命名服务,应用程序可以通过名字来找到所需的服务。
  4. 集群管理:ZooKeeper可以用来管理分布式集群,协调各个节点的加入与退出。
  5. Master选举:ZooKeeper可以用来实现Master选举,选择一个节点作为Master节点。
  6. 分布式协调服务:ZooKeeper提供了一些分布式协调服务,如分布式锁、唯一标识生成等,帮助系统的各个组件之间进行协调。
  7. 服务注册与发现:ZooKeeper可以用来注册和发现系统中的服务,简化服务的部署和更新。
  8. 负载均衡:ZooKeeper可以用来动态地对请求进行负载均衡,以提高系统的可用性。

2.ZooKeeper概念

2.1ZooKeeper数据模型

ZooKeeper数据模型采用层次化的多叉树形结构,每个节点上都可以存储数据,这些数据可以是数字、字符串或者是二进制序列。每个节点还可以拥有N个子节点,最上层是根节点以“/”来代表。每个数据节点在ZooKeeper中被称为znode,它是ZooKeeper中数据的最小单元。并且,每个znode都有一个唯一的路径标识。

==强调一句:ZooKeeper主要是用来协调服务的,而不是用来存储业务数据的,所以不要放比较大的数据在znode上,ZooKeeper给出的每个节点的数据大小上限是1M。==

2.2ZooKeeper节点类型

  • 持久(PERSISTENT)节点:一旦创建就一直存在即使ZooKeeper集群宕机,直到将其删除。

  • 临时(EPHEMERAL)节点:临时节点的生命周期是与客户端会话(session)绑定的,会话消失则节点消失。并且,临时节点只能做叶子节点,不能创建子节点。

  • 持久顺序(PERSISTENT_SEQUENTIAL)节点:除了具有持久(PERSISTENT)节点的特性之外,子节点的名称还具有顺序性。

  • 临时顺序(EPHEMERAL_SEQUENTIAL)节点:除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性。

每个znode由2部分组成:stat-状态信息;data:节点存放的数据内容。

image-20240208145637424

==验证pZxid、cversion和numChildren的意义==

image-20240208150743452

==验证mZxid、dataVersion和dataLength的意义==

image-20240208151033647

==验证pZxid、numChildren和ephemeralOwner的意义==

image-20240208152018421

image-20240208152332442

2.3ZooKeeper的ACL权限控制

ZooKeeper采用ACL(AccessControlLists)策略来进行权限控制,类似于UNIX文件系统的权限控制。

对于znode操作的权限,ZooKeeper提供了以下5种:

  • CREATE: 能创建子节点
  • READ:能获取节点数据和列出其子节点
  • WRITE: 能设置/更新节点数据
  • DELETE: 能删除子节点
  • ADMIN: 能设置节点ACL的权限

其中尤其需要注意的是,CREATE和DELETE这两种权限都是针对子节点的权限控制。

对于身份认证,提供了以下几种方式:

  • world:默认方式,所有用户都可无条件访问。
  • auth:不使用任何id,代表任何已认证的用户。
  • digest:用户名:密码认证方式:username:password。
  • ip: 对指定ip进行限制。

2.4ZooKeeper的Watcher机制

Watcher(事件监听器),是ZooKeeper中的一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是ZooKeeper实现分布式协调服务的重要特性。

ZooKeeper Watcher 机制

2.5ZooKeeper的会话

Session可以看作是ZooKeeper服务器与客户端的之间的一个TCP长连接,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向ZooKeeper服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的Watcher事件通知。

Session有一个属性叫做:sessionTimeoutsessionTimeout代表会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在sessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。

另外,在为客户端创建会话之前,服务端首先会为每个客户端都分配一个sessionID。由于 sessionID是ZooKeeper会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID的,因此,无论是哪台服务器为客户端分配的sessionID,都务必保证全局唯一。

3.ZooKeeper集群

为了保证高可用,最好是以集群形态来部署ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么ZooKeeper本身仍然是可用的。通常3台服务器就可以构成一个 ZooKeeper集群了。ZooKeeper官方提供的架构图就是一个ZooKeeper集群整体对外提供服务。

ZooKeeper 集群架构

上图中每一个Server代表一个安装ZooKeeper服务的服务器。组成ZooKeeper服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。集群间通过ZAB协议(ZooKeeper Atomic Broadcast)来保持数据的一致性。

最典型集群模式:Master/Slave 模式(主备模式)。在这种模式中,通常Master服务器作为主服务器提供写服务,其他的Slave服务器作为从服务器通过异步复制的方式获取Master服务器最新的数据,并提供读服务。

3.1ZooKeeper的集群角色

在ZooKeeper中没有选择传统的Master/Slave概念,而是引入了Leader、Follower和Observer三种角色。

ZooKeeper 集群中角色

ZooKeeper集群中的所有机器通过一个Leader选举过程来选定一台称为“Leader”的机器,Leader既可以为客户端提供写服务又能提供读服务。除了Leader外,FollowerObserver都只能提供读服务。

Follower和Observer唯一的区别在于Observer机器不参与Leader的选举过程,也不参与写操作的“过半写成功”策略,因此Observer机器可以在不影响写性能的情况下提升集群的读性能

image-20240208153629303

3.2ZooKeeper的选举流程

注意如果Zookeeper是单机部署是不需要选举的,集群模式下才需要选举。

Zookeeper的选举原理和人类选举的逻辑类似,套用一下人类选举的四个基本概念详细解释一下Zookeeper。

  • 个人能力

如何衡量Zookeeper节点个人能力?答案是靠数据是否够新,如果节点的数据越新就代表这个节点的个人能力越强,是不是感觉很奇怪,就是这么定的!

在Zookeeper中通常是以事务id(后面简称zxid)来标识数据的新旧程度(版本),节点新的zxid越大代表这个节点的数据越新,也就代表这个节点能力越强。

zxid 的全称是 ZooKeeper Transaction Id,即 Zookeeper 事务id。

  • 遇强改投

在集群选举开始时,节点首先认为自己是强的(即数据是新的),然后在选票上写上自己的名字(包括zxidsid),zxid是事务id,sid标识自己。

紧接着会将选票传递给其他节点,同时自己也会接收其他节点传过来的选票。每个节点接收到选票后会做比较,这个人是不是比我强(zxid比我大),如果比较强,那我就需要改票,明明别人比我强,我也不能厚着脸皮对吧。

  • 投票箱

与人类选举投票箱稍微有点不一样,Zookeeper集群会在每个节点的内存中维护一个投票箱。节点会将自己的选票以及其他节点的选票都放在这个投票箱中。由于选票是互相传阅的,所以终每个节点投票箱中的选票会是一样的。

  • 服从多数

在投票的过程中会去统计是否有超过一半的选票和自己选择的是同一个节点,即都认为某个节点是强的。一旦集群中有超过半数的节点都认为某个节点强,那该节点就是了,投票也宣告结束。


🤖什么场景下Zookeeper需要选举?


当Zookeeper集群中的一台服务器出现以下两种情况之一时,需要进入Leader选举

(1)服务器初始化启动。

(2)服务器运行期间Leader故障。

启动期间的Leader选举

假设一个Zookeeper集群中有5台服务器,id从1到5编号,并且它们都是新启动的,没有历史数据。假设服务器依次启动,我们来分析一下选举过程:

img

(1)服务器1启动

发起一次选举,服务器1投自己一票,此时服务器1票数一票,不够半数以上(3票),选举无法完成。

投票结果:服务器1为1票。

服务器1状态保持为LOOKING

(2)服务器2启动

发起一次选举,服务器1和2分别投自己一票,此时服务器1发现服务器2的id比自己大,更改选票投给服务器2。

投票结果:服务器1为0票,服务器2为2票。

服务器1,2状态保持LOOKING

(3)服务器3启动

发起一次选举,服务器1、2、3先投自己一票,然后因为服务器3的id大,两者更改选票投给为服务器3;

投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数(3票),服务器3当选Leader

服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING

(4)服务器4启动

发起一次选举,此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3。

服务器4并更改状态为FOLLOWING

(5)服务器5启动

与服务器4一样投票给3,此时服务器3一共5票,服务器5为0票。

服务器5并更改状态为FOLLOWING

最终的结果

服务器3是Leader,状态为LEADING;其余服务器是Follower,状态为FOLLOWING

运行期间的Leader选举

在Zookeeper运行期间Leader非 Leader各司其职,当有非Leader服务器宕机或加入不会影响Leader,但是一旦Leader服务器挂了,那么整个Zookeeper集群将暂停对外服务,会触发新一轮的选举。

初始状态下服务器3当选为Leader,假设现在服务器3故障宕机了,此时每个服务器上zxid可能都不一样,server1为99,server2为102,server4为100,server5为101。

img

运行期选举与初始状态投票过程基本类似,大致可以分为以下几个步骤:

(1)状态变更。Leader故障后,余下的非Observer服务器都会将自己的服务器状态变更为LOOKING,然后开始进入Leader选举过程

(2)每个Server会发出投票。

(3)接收来自各个服务器的投票,如果其他服务器的数据比自己的新会改投票。

(4)处理和统计投票,每一轮投票结束后都会统计投票,超过半数即可当选。

(5)改变服务器的状态,宣布当选。

img


🧶选举机制中涉及到的核心概念


(1)Server id:服务器ID

比如有三台服务器,编号分别是1,2,3。编号越大在选择算法中的权重越大,比如初始化启动时就是根据服务器ID进行比较。

(2)Zxid:事务ID

服务器中存放的数据的事务ID,值越大说明数据越新,在选举算法中数据越新权重越大。

(3)Epoch:逻辑时钟

也叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的,每投完一次票这个数据就会增加。