读书笔记-zookeeper分布式过程

zookeeper的基本概念和基础

  • 使⽤ZooKeeper来设计应⽤时,最好将应⽤数据和协同数据独⽴开。⽐如,⽹络邮箱服务的⽤户对⾃⼰邮箱中的内容感兴趣,但是并不关⼼由哪台服务器来处理特定邮箱的请求。在这个例⼦中,邮箱内容就是应⽤数据,⽽从邮箱到某⼀台邮箱服务器之间的映射关系就是协同数据(或称元数据)

  • 持久节点和临时节点: 持久的znode,如/path,只能通过调⽤delete来进⾏删除。临时的znode与之相反,当创建该节点的客户端崩溃或关闭了与ZooKeeper的连接时,这个节点就会被删除,临时节点没有子节点

  • 有序节点: 被分配唯⼀个单调递增的整数

  • znode⼀共有4种类型:持久的(persistent)、临时的(ephemeral)、持久有序的(persistent_sequential)和临时有序的(ephemeral_sequential)

  • 版本:每⼀个znode都有⼀个版本号,它随着每次数据变化⽽⾃增

  • 通过ZooKeeper实现锁: 需要新建临时节点而不是持久节点,如果申请持久节点,如果zookeeper崩溃,将导致应用程序因为死锁而失灵

  • ZooKeeper中实现了⼀组核⼼操作,通过这些可以实现很多常见分布式应⽤的任务

  • 实现主-从模式关键问题:主节点崩溃,从节点崩溃,通信故障

  • 主节点崩溃

主节点失效时,我们需要有⼀个备份主节点(backup master)。当主
要主节点(primary master)崩溃时,备份主节点接管主要主节点的⾓⾊,
进⾏故障转移,然⽽,这并不是简单开始处理进⼊主节点的请求。新的主
要主节点需要能够恢复到旧的主要主节点崩溃时的状态。对于主节点状态
的可恢复性,我们不能依靠从已经崩溃的主节点来获取这些信息,⽽需要
从其他地⽅获取,也就是通过ZooKeeper来获取

  • 从节点崩溃

客户端向主节点提交任务,之后主节点将任务派发到有效的从节点
中。从节点接收到派发的任务,执⾏完这些任务后会向主节点报告执⾏状
态。主节点下⼀步会将执⾏结果通知给客户端。
如果从节点崩溃了,所有已派发给这个从节点且尚未完成的任务需要
重新派发。其中⾸要需求是让主节点具有检测从节点的崩溃的能⼒。主节
点必须能够检测到从节点的崩溃,并确定哪些从节点是否有效以便派发崩
溃节点的任务。⼀个从节点崩溃时,从节点也许执⾏了部分任务,也许全
部执⾏完,但没有报告结果。如果整个运算过程产⽣了其他作⽤,我们还
有必要执⾏某些恢复过程来清除之前的状态。

  • 通信故障

如果⼀个从节点与主节点的⽹络连接断开,⽐如⽹络分区(network
partition)导致,重新分配⼀个任务可能会导致两个从节点执⾏相同的任
务。如果⼀个任务允许多次执⾏,我们在进⾏任务再分配时可以不⽤验证
第⼀个从节点是否完成了该任务。如果⼀个任务不允许,那么我们的应⽤
需要适应多个从节点执⾏相同任务的可能性

·/workers节点作为⽗节点,其下每个znode⼦节点保存了系统中⼀个可
用从节点信息。如图2-1所示,有⼀个从节点(foot.com:2181)。
·/tasks节点作为⽗节点,其下每个znode⼦节点保存了所有已经创建并
等待从节点执⾏的任务的信息,主-从模式的应用的客户端在/tasks下添加
⼀个znode⼦节点,用来表示⼀个新任务,并等待任务状态的znode节点。
·/assign节点作为⽗节点,其下每个znode⼦节点保存了分配到某个从
节点的⼀个任务信息,当主节点为某个从节点分配了⼀个任务,就会
在/assign下增加⼀个⼦节点。
  • ZooKeeper并不允许局部写⼊或读取znode节点的数据。当设置⼀个znode节点的数据或读取时,znode节点的内容会被整个替换或全部读取进来。

通知(notification)的机制:客户端向ZooKeeper注册需要接收通知的znode,通过对znode设置监视点(watch)来接收通知。监视点是⼀个单次触发的操作,意即监视点会触发⼀个通知。
为了接收多个通知,客户端必须在每次通知后设置⼀个新的监视点。

每⼀个znode都有⼀个版本号,它随着每次数据变化⽽⾃增。两个API
操作可以有条件地执⾏:setData和delete。这两个调⽤以版本号作为转⼊参
数,只有当转⼊参数的版本号与服务器上的版本号⼀致时调⽤才会成功。
当多个ZooKeeper客户端对同⼀个znode进⾏操作时,版本的使⽤就会显得
尤为重要。例如,假设客户端c 1 对znode/config写⼊了⼀些配置信息,如果
另⼀个客户端c 2 同时更新了这个znode,此时c 1 的版本号已经过期,c 1 调⽤
setData⼀定不会成功。使⽤版本机制有效避免了以上情况。在这个例⼦
中,c1 在写⼊数据时使⽤的版本⽆法匹配,使得操作失败,

例如,我们⼀共有5个ZooKeeper服务
器,但法定⼈数为3个,这样,只要任何3个服务器保存了数据,客户端就
可以继续,⽽其他两个服务器最终也将捕获到数据,并保存数据

如果有5个服务器,可以容许最多
f=2个崩溃。在集合中,服务器的个数并不是必须为奇数,只是使⽤偶数会
使得系统更加脆弱。假设在集合中使⽤4个服务器,那么多数原则对应的数
量为3个服务器。然⽽,这个系统仅能容许1个服务器崩溃,因为两个服务
器崩溃就会导致系统失去多数原则的状态。因此,在4个服务器的情况下,
我们仅能容许⼀个服务器崩溃,⽽法定⼈数现在却更⼤,这意味着对每个
请求,我们需要更多的确认操作。底线是我们需要争取奇数个服务器。

创建⼀个会话时,你需要设置会话超时这个重要的参数,这个参数设
置了ZooKeeper服务允许会话被声明为超时之前存在的时间。如果经过时间
t之后服务接收不到这个会话的任何消息,服务就会声明会话过期。⽽在客
户端侧,如果经过t/3的时间未收到任何消息,客户端将向服务器发送⼼跳
消息。在经过2t/3时间后,ZooKeeper客户端开始寻找其他的服务器,⽽此
时它还有t/3时间去寻找。

  • 如果⼀个客户端在位置i观察到⼀个更新,它就不能连接到只观察到i'<i的服务器上。在ZooKeeper实现中,系统根据每⼀个更新建⽴的顺序来分配给事务标识符。

  • 系统中任何时候都可能发⽣新的从节点加⼊进来,或旧的从节点退役的情况,从节点执⾏分配给它的任务前也许会崩溃。
    为了确认某个时间点可⽤的从节点信息,我们通过在ZooKeeper中的/workers下添加⼦节点来注册新的从节点。
    当⼀个从节点崩溃或从系统中被移除,如会话过期等情况,需要⾃动将对应的znode节点删除。优雅实现的从节点会显式地关闭其会话,⽽不需要ZooKeeper等待会话过期。

  • Multiop可以原⼦性地执⾏多个ZooKeeper的操作,执⾏过程为原⼦性,即在multiop代码块中的所有操作要不全部成功,要不全部失败。
    例如,我们在⼀个multiop块中删除⼀个⽗节点以及其⼦节点,执⾏结果只可能是这两个操作都成功或都失败,⽽不可能是⽗节点被删除⽽⼦节点还存在,或⼦节点被删除⽽⽗节点还存在。

从应⽤的⾓度来看,客户端每次都是通过访问ZooKeeper来获取给定
znode节点的数据、⼀个znode节点的⼦节点列表或其他相关的ZooKeeper状
态,这种⽅式并不可取。反⽽更⾼效的⽅式为客户端本地缓存数据,并在
需要时使⽤这些数据,⼀旦这些数据发⽣变化,你让ZooKeeper通知客户
端,客户端就可以更新缓存的数据。这些通知与我们之前所讨论的⼀样,
应⽤的客户端通过注册监视点来接收这些通知消息。总之,监视点可以让
客户端在本地缓存⼀个版本的数据(⽐如,⼀个znode节点数据或节点的⼦
节点列表信息),并在数据发⽣变化时接收到通知来进⾏更新。

每个服务器启动后进⼊LOOKING状态,开始选举⼀个新的群⾸或查
找已经存在的群⾸,如果群⾸已经存在,其他服务器就会通知这个新启动
的服务器,告知哪个服务器是群⾸,与此同时,新的服务器会与群⾸建⽴
连接,以确保⾃⼰的状态与群⾸⼀致。
如果集群中所有的服务器均处于LOOKING状态,这些服务器之间就
会进⾏通信来选举⼀个群⾸,通过信息交换对群⾸选举达成共识的选择。
在本次选举过程中胜出的服务器将进⼊LEADING状态,⽽集群中其他服务
器将会进⼊FOLLOWING状态。

zookeeper总结

Zookeeper 怎么保证主从节点的状态同步?

  • Zookeeper 的核心是原子广播机制,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式和广播模式。
  • 恢复模式
    当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。
  • 广播模式
    一旦 leader 已经和多数的 follower 进行了状态同步后,它就可以开始广播消息了,即进入广播状态。这时候当一个 server 加入 ZooKeeper 服务中,它会在恢复模式下启动,发现 leader,并和 leader 进行状态同步。待到同步结束,它也参与消息广播。ZooKeeper 服务一直维持在 Broadcast 状态,直到 leader 崩溃了或者 leader 失去了大部分的 followers 支持。

四种类型的数据节点 Znode

  • PERSISTENT-持久节点
    ​ 除非手动删除,否则节点一直存在于 Zookeeper 上

  • EPHEMERAL-临时节点
    ​ 临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。

  • PERSISTENT_SEQUENTIAL-持久顺序节点
    ​ 基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

  • EPHEMERAL_SEQUENTIAL-临时顺序节点
    ​ 基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

Zookeeper Watcher 机制 – 数据变更通知

Zookeeper 允许客户端向服务端的某个 Znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。
工作机制:
(1)客户端注册 watcher
(2)服务端处理 watcher
(3)客户端回调 watcher

Zookeeper 下 Server 工作状态

(1)LOOKING:寻 找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。
(2)FOLLOWING:跟随者状态。表明当前服务器角色是 Follower。
(3)LEADING:领导者状态。表明当前服务器角色是 Leader。
(4)OBSERVING:观察者状态。表明当前服务器角色是 Observer。

zookeeper 是如何保证事务的顺序一致性的?

zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch( 时期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch会自增,低 32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

zk 节点宕机如何处理?

Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。Zookeeper 自身也要保证当一个节点宕机时,其他节点会继续提供服务。
如果是一个 Follower 宕机,还有 2 台服务器提供访问,因为 Zookeeper 上的数据是有多个副本的,数据并不会丢失;
如果是一个 Leader 宕机,Zookeeper 会选举出新的 Leader。
ZK 集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在 ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。
3 个节点的 cluster 可以挂掉 1 个节点(leader 可以得到 2 票>1.5)
2 个节点的 cluster 就不能挂掉任何 1 个节点了(leader 可以得到 1 票<=1)

zookeeper 负载均衡和 nginx 负载均衡区别

zk 的负载均衡是可以调控,nginx 只是能调权重,其他需要可控的都需要自己写插件;但是 nginx 的吞吐量比 zk 大很多,应该说按业务选择用哪种方式。

Zookeeper 有哪几种几种部署模式?

Zookeeper 有三种部署模式:
单机部署:一台集群上运行;
集群部署:多台集群运行;
伪集群部署:一台集群启动多个 Zookeeper 实例运行。

集群最少要几台机器,集群规则是怎样的?集群中有 3 台服务器,其中一个节点宕机,这个时候 Zookeeper 还可以使用吗?

集群规则为 2N+1 台,N>0,即 3 台。可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。

集群支持动态添加机器吗?

其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:
全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。
逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。
3.5 版本开始支持动态扩容。

Zookeeper 对节点的 watch 监听通知是永久的吗?为什么不是永久的?

不是。官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它们。
为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,给网络和服务器造成很大压力。
一般是客户端执行 getData(“/节点 A”,true),如果节点 A 发生了变更或删除,客户端会得到它的 watch 事件,但是在之后节点 A 又发生了变更,而客户端又没有设置 watch 事件,就不再给客户端发送。
在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。

  • 常用命令:ls get set create delete 等

ZAB 和 Paxos 算法的联系与区别?

相同点:
(1)两者都存在一个类似于 Leader 进程的角色,由其负责协调多个 Follower 进程的运行
(2)Leader 进程都会等待超过半数的 Follower 做出正确的反馈后,才会将一个提案进行提交
(3)ZAB 协议中,每个 Proposal 中都包含一个 epoch 值来代表当前的 Leader周期,Paxos 中名字为 Ballot
不同点:
ZAB 用来构建高可用的分布式数据主备系统(Zookeeper),Paxos 是用来构建分布式一致性状态机系统。

Zookeeper 的典型应用场景

数据发布/订阅

数据发布/订阅系统,即所谓的配置中心,顾名思义就是发布者发布数据供订阅者进行数据订阅。
目的
动态获取数据(配置信息)
实现数据(配置信息)的集中式管理和数据的动态更新
数据(配置信息)特性
1)数据量通常比较小
2)数据内容在运行时会发生动态更新
3)集群中各机器共享,配置一致

基于 Zookeeper 的实现方式

· 数据存储:将数据(配置信息)存储到 Zookeeper 上的一个数据节点
· 数据获取:应用在启动初始化节点从 Zookeeper 数据节点读取数据,并在该节点上注册一个数据变更 Watcher
· 数据变更:当变更数据时,更新 Zookeeper 对应节点数据,Zookeeper会将数据变更通知发到各客户端,客户端接到通知后重新读取变更后的数据即可。

负载均衡

zk 的命名服务
命名服务是指通过指定的名字来获取资源或者服务的地址,利用 zk 创建一个全局的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地址,或者一个远程的对象等等。

Zookeeper 分布式锁(文件系统、通知机制)

  • 有了 zookeeper 的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

  • 对于第一类,我们将 zookeeper 上的一个 znode 看作是一把锁,通过 createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的 distribute_lock 节点就释放出锁。

  • 对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选 master 一样,编号最小的获得锁,用完删除,依次方便。

Zookeeper 队列管理(文件系统、通知机制)

两种类型的队列:
(1)同步队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。
(2)队列按照 FIFO 方式进行入队和出队操作。
第一类,在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。
第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。在特定的目录下创建 PERSISTENT_SEQUENTIAL 节点,创建成功时Watcher 通知等待的队列,队列删除序列号最小的节点用以消费。此场景下Zookeeper 的 znode 用于消息存储,znode 存储的数据就是消息队列中的消息内容,SEQUENTIAL 序列号就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。

Zookeeper 都有哪些功能?

  • 集群管理:监控节点存活状态、运行请求等;
  • 主节点选举:主节点挂掉了之后可以从备用的节点开始新一轮选主,主节点选举说的就是这个选举的过程,使用 Zookeeper 可以协助完成这个过程;
  • 分布式锁:Zookeeper 提供两种锁:独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,即可以有多线线程同时读同一个资源,如果要使用写锁也只能有一个线程使用。Zookeeper 可以对分布式锁进行控制。
  • 命名服务:在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。
posted @ 2020-12-01 10:16  余***龙  阅读(109)  评论(0编辑  收藏  举报