Zookeeper知识点详解


目录

  1. ZooKeeper 集群原理

  2. ZooKeeper 分布式锁

  3. ZooKeeper 分布式事务

  4. ZooKeeper 选举原理

  5. Paxos 协议

  6. ZAB 协议

  7. ZooKeeper 会话管理

  8. ZooKeeper 的 Watcher 机制

  9. ZooKeeper 的应用场景


1. ZooKeeper 集群原理

关于 ZooKeeper,官网给出的一句话定义:

A Distributed Coordination Service for Distributed Applications

简单地说,ZooKeeper 是一个分布式应用程序协调服务。

ZooKeeper 集群设计原则:

  1. 最终一致性:客户端无论连接哪个 ZK 节点,读到的数据最终一定是相同的。
  2. 可靠性:客户端无论往哪个 ZK 节点写数据,数据最终一定会同步到其他节点。
  3. 实时性:由于 ZK 复制数据带来一定的延迟,客户端可以调用 sync() 拉取最新数据。
  4. 独立性:ZK 集群允许多客户端并发执行任务。
  5. 原子性:对于同一份数据,不存在一部分节点写成功,另一部分节点写失败。
  6. 顺序性:ZK 为每一个写事务分配全局自增 zxid,保证写入消息依然保持有序。

2. ZooKeeper 分布式锁

ZooKeeper 分布式锁有两个核心要素:临时有序节点和 Watcher 事件监听。

首先,什么是临时有序节点?ZK 底层数据结构是一棵树,由节点 Znode 组成,Znode 分四种类型:

  1. 持久节点 (PERSISTENT):默认类型,节点一旦创建,即便客户端失去连接,节点依然保留。
  2. 临时节点(EPHEMERAL) :与持久节点相反,客户端失去连接,节点被 ZK 自动删除。
  3. 持久节点顺序节点(PERSISTENT_SEQUENTIAL):ZK 按创建时间给持久节点编号。
  4. 临时顺序节点(EPHEMERAL_SEQUENTIAL):ZK 按创建时间给临时节点编号。
public enum CreateMode {PERSISTENT(0, false, false),PERSISTENT_SEQUENTIAL(2, false, true),EPHEMERAL(1, true, false),EPHEMERAL_SEQUENTIAL(3, true, true);
}

其次,什么是 Watcher?简单地说,Watcher 是一种事件监听机制。客户端在读写数据时,可以对 ZK 节点注册事件监听器 Watcher。一旦 ZK 节点数据或结构变化,ZooKeeper 会触发相应的事件 WatchEvent,通知客户端 Watcher 接口的回调方法 process()。

public interface Watcher {abstract public void process(WatchedEvent event);
}

接下来,我们看看什么是分布式锁?相对于 JVM 锁,分布式锁的特点是跨 JVM 的,这两张图可以说明。

下面,举例说明 ZooKeeper 是如何实现分布式锁的。

假设有三个进程同时访问一个临界区资源,我们需要 ZooKeeper 分布式锁做并发控制,同一时刻只允许同一个进程访问。我们把三个进程当成三个 ZK 的客户端,分别创建三个 ZK 临时有序节点:Lock1、Lock2、Lock3,挂在 ParentLock 节点下面,其中 Lock1 节点编号最小,Lock3 节点编号最大。已知 Client1 获取锁,Client2 与 Client3 分别注册 Watch 监听器,其中 Client2 监听 Lock1 节点,Client3 监听 Lock2 节点。

假设 Client1 完成任务,断开连接,释放锁,ZK 自动删除 Lock1 节点,产生事件,触发 Client2 的监听器 Watcher 回调。此时,Client2 会再次查询 ParentLock 下面的所有节点,确认自己创建的节点 Lock2 是否为最小节点,如果是,则 Client2 顺利成章获取了锁。

最后看一下获取锁的代码:

public boolean tryLock() {String node = zk.create("ParentLock/", CreateMode.EPHEMERAL_SEQUENTIAL);List<String> allNodes = zk.getChildren("ParentLock");Collections.sort(allNodes);if(allNodes.get(0).equals(nodeName)){//当前结点是最小的节点,获取锁成功return true;} else{//监听最小的结点zk.exists(allNodes.get(0), new Watcher() {public void process(WatchedEvent event) {if(event.getType() == EventType.NodeDeleted){...}}return false;               }

3. ZooKeeper 分布式事务

ZooKeeper 实现分布式事务,类似于两阶段提交,总共分四个步骤:

步骤 #1:客户端先向 ZK 节点发送写请求。
步骤 #2:ZK 节点将写请求转发给 Leader 节点,Leader 广播给集群要求投票,等待确认。
步骤 #3:Leader 收到确认,统计投票,票数过半则提交事务。
步骤 #4:事务提交成功后,ZK 节点告知客户端。


4. ZooKeeper 选举原理

先来明确一下概念:

sid(serverId):比如有三台服务器,编号分别是 1、2、3。编号越大,在选择算法中的权重越大。
zxid(最新的事务 ID ):ID 值越大说明数据越新,在选举算法中数据越新权重越大。
epoch (逻辑时钟 ):同一轮投票的逻辑时钟值是相同的。每投完一次票这个数据就会增加。
选举状态:LOOKING 竞选;FOLLOWING 随从,投票;OBSERVING 观察,不投票;LEADING 领导者。
vote_sid:对方投票推举 Leader 的服务器 sid。
vote_zxid:对方投票推举 Leader 的服务器 zxid。
self_sid:当前服务器的 sid。
self_zxid:当前服务器的 zxid。

规则如下:

  1. 如果 vote_zxid 大于自己的 self_zxid,就认可当前收到的投票,并再次将该投票发送出去。
  2. 如果 vote_zxid 小于自己的 self_zxid,那么就坚持自己的投票,不做任何变更。
  3. 如果 vote_zxid 等于自己的 self_zxid,那么就对比两者的 sid,重复 规则1 或者 规则2。

我们假设 ZooKeeper 集群由 5 台机器组成,sid 分別为 1、2、3、4 和 5,zxid 分别为 9、9、9、8 和 8,2 号机器是 Leader。某一时刻,1 号和 2 号机器宕机,因此集群开始进行 Leader 选举。

第一轮投票,epoch=1。

由于机器彼此不知对方的状态,因此每台机器都将票投给自己。投票情况分别为:(3, 9)、(4, 8)和(5, 8)。每台机器都把投票发出后,同时也会接收到来自另外两台机器的投票。

第二轮投票,epoch=2。

对干 3 号机器,接收(4, 8)和(5, 8)两张投票,发现 self_zxid=9 大于 vote_zxid=8,因此无需变更。

对于 4 号机器,接收(3, 9)和(5, 8)两张投票,发现 self_zxid=8 小于 vote_zxid=9,认可并变更投票为(3, 9),再次将这张票投出去。

5 号机器与 4 号类似,认可并变更投票为(3, 9),再次将这张票投出去。

两轮投票过后,投票桶的票数为 3,已过半数,3 号晋升为 Leader,其余退化为 Follower。


5. Paxos 协议

ZooKeeper 分布式一致性算法的原型,就是 Paxos 协议。下面简单分析一下 Paxos 协议。Paxos 中有三类角色 Proposer、Acceptor 及 Learner,相当于 ZooKeeper 集群中的 Leader、Follower 和 Observer。

简单地说,Paxos 的原理是:Proposer 将发起提案(value)给所有 Accpetor,超过半数 Accpetor 获得批准后,Proposer 将提案写入 Accpetor 内,最终所有 Accpetor 获得一致性的确定性取值,且后续不允许再修改。

这 4 类消息对应于 Paxos 算法的两个阶段 4 个过程,如下图:


Paxos 在原作者的 Paxos Made Simple 中内容是比较精简的:


Phase 1

(a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.
(a) Proposer 选择一个提议编号 n,向超半数 Acceptor 广播 Prepare(n)请求。

(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered pro-posal (if any) that it has accepted.
(b) Acceptor 接收到 Prepare(n)请求,若提议编号 n 比之前接收的 Prepare 请求都要大,则承诺将不会接收提议编号比 n 小的提议,并且带上之前 Accept 的提议中编号小于 n 的最大的提议,否则不予理会。

Phase 2

(a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v , where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.
(a) Proposer 得到了 Acceptor 响应,如果未超过半数 Accpetor 响应,直接转为提议失败;如果超过多数 Acceptor 的承诺,又分为不同情况:如果所有 Acceptor 都未接收过值(都为 null),那么向所有的 Acceptor 发起自己的值和提议编号 n;如果有部分 Acceptor 接收过值,那么从所有接受过的值中选择对应的提议编号最大的作为提议的值,提议编号仍然为 n。但此时 Proposer 就不能提议自己的值,只能信任 Acceptor 通过的值 v,维护一但获得确定性取值就不能更改原则;

(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.
(b) Acceptor 接收到提议后,如果该提议版本号不等于自身保存记录的版本号(第一阶段记录的),不接受该请求,相等则写入本地。


6. ZAB 协议

ZAB 是 ZooKeeper Atomic Broadcast 简称,是 ZooKeeper 实现一致性的理论依据。原文写得非常简单,只有非常笼统的框架,没有细节。

ZAB 分为两个部分:Broadcast 和 Recovery。

当系统启动或者leader服务器出现故障等现象时,进入故障恢复模式。将会开启新的一轮的选举。选举产生的leader会与过半的follower进行同步,保持数据一致。当同步结束后,退出恢复模式,进入消息广播模式。当一台遵循ZAB协议的服务器启动后,如果检测到有leader在广播消息,会自动进入恢复模式,当其完成与leader的同步以后,进入消息广播模式。如果集群中的非leader 节点收到客户端请求,非leader会先将请求发送到leader服务器。

先说一下 Broadcast 广播机制。

Leader 接受所有写请求;超过半数 Follower 进行 Ack 确认后,Leader 发送 Commit。类似于简化版的二阶段协议。Leader 用 zxid 保证消息的顺序性。Follower 存入硬盘后 Ack,在接收到 Commit 后开始服务 Client。Client 读 in-memory 的数据。

再说一下 Recovery 恢复机制。

刚刚我们说消息广播过程中,Leader 崩溃(崩溃即 Leader 失去与过半 Follwer 的联系)怎么办?还能保证数据一致吗?

针对这些问题,ZAB 定义了 2 个原则:

  • ZAB 协议确保那些已经在 Leader 提交的事务最终会被所有服务器提交。
  • ZAB 协议确保丢弃那些只在 Leader 提出/复制,但没有提交的事务。


7. ZooKeeper 会话管理

Session 指的是 ZooKeeper 服务器与客户端会话,换句话说,指的是客户端和服务端之间的一次 TCP 长连接。

客户端启动时,会与服务器建立 TCP 连接,此时客户端会话的生命周期就开始了。通过 Session,客户端能够用 ping-pong 心跳检测与服务端保持连接,客户端可以向 ZK 发送请求并接受响应,同时 ZK 还能通过 Watch 向客户端推送通知。

Session 的 sessionTimeout 参数用来设置一个客户端会话的超时时间。由于网络故障或客户端主动断开连接时,只要在 sessionTimeout 有效期内重连任意机器,那么此前创建的会话仍然有效。

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


8. ZooKeeper 的 Watcher 机制

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

public interface Watcher {abstract public void process(WatchedEvent event);
}

ZooKeeper 的 Watcher 有几个特点:

  • 一次性:一旦一个 Watcher 被触发,ZooKeeper 就会将其从相应的存储中移除,所以使用时要反复注册。
  • 客户端串行:执行 Watcher 回调的过程是一个串行执行的过程,从而保证了顺序。
  • 轻量:客户端向服务端注册 Watcher 的时候,并不会把客户端真实的 Watcher 对象实体传递到服务端,仅仅是在客户端请求中使用 boolean 类型属性进行了标记。Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。

9. ZooKeeper 的应用场景

发布/订阅

应用启动时主动去 ZooKeeper 获取配置信息,并注册一个 Watcher 监听配置发生变更时,ZooKeeper 服务端会通知所有订阅的客户端,客户端收到通知后,主动到服务端获取最新数据。

全局唯一

ID 利用顺序节点的特性,创建一个顺序节点,根据返回的完整节点名,作为 ID 即可。

Master 选举

  • 开始选举,即所有机器都作为 ZooKeeper 向 ZooKeeper 集群请求创建一个临时节点,成功创建该节点的机器,成为 Master。
  • 其他创建失败的客户端对应的机器,都会在该节点上注册一个 Watcher,用于监控当前的 Master 机器是否存活。
  • 一旦发现当前的 Master 挂了(即收到 Watcher 事件通知节点被删除),则重新选举。

分布式锁

  • 排他锁:和 Master 选举类似,利用临时节点的特性。创建临时节点成功的客户端获得锁,客户端意外挂掉则临时节点被自动删除或者是正常结束业务逻辑然后主动删除节点,此时 ZooKeeper 会通知其他客户端再次争夺锁。
  • 共享锁:利用顺序节点的特性。对于读写请求,分别创建临时顺序节点。下面重要的是判断读写顺序——对于读请求,如果有比自己序号小的写请求,则进入等待,否则执行读取逻辑;对于写请求,如果自己不是最小的序号,则进入等待。

Zookeeper知识点详解相关推荐

  1. python 消息队列 get是从队首还是队尾取东西_python分布式爬虫中消息队列知识点详解...

    当排队等待人数过多的时候,我们需要设置一个等待区防止秩序混乱,同时再有新来的想要排队也可以呆在这个地方.那么在python分布式爬虫中,消息队列就相当于这样的一个区域,爬虫要进入这个区域找寻自己想要的 ...

  2. 分布式锁(基于redis和zookeeper)详解

    分布式锁(基于redis和zookeeper)详解 https://blog.csdn.net/a15835774652/article/details/81775044 为什么写这篇文章? 目前网上 ...

  3. mysql text类型 使用方法_MySQL使用TEXT/BLOB类型的知识点详解

    一.TEXT和BLOB的区别 TEXT和BLOB家族之间仅有的不同是BLOB类型存储的是二进制数据,没有排序规则或字符集,而TEXT类型有字符集或排序规则.说白了如果要储存中文则选择TEXT. 二.默 ...

  4. python源程序文件的扩展名_python程序文件扩展名知识点详解

    python程序文件的扩展名称是什么 python程序的扩展名有.py..pyc..pyo和.pyd..py是源文件,.pyc是源文件编译后的文件,.pyo是源文件优化编译后的文件,.pyd是其他语言 ...

  5. java中流_Java中流的有关知识点详解

    Java中流的有关知识点详解 发布时间:2020-09-17 03:50:59 来源:脚本之家 阅读:103 作者:mumu1998 什么是流? 流:程序和设备之间连接起来的一根用于数据传输的管道,流 ...

  6. design短语的用法总结_最新高中英语知识点详解之design的用法及常见短语

    英语的应用越来越广泛了,我们必须好好来学习英语知识.对此小学频道编辑为大家整理了最新高中英语知识点详解之design的用法及常见短语.详情如下: design的用法 n.设计;图案;构思 vt.设计; ...

  7. 学习电气自动化PLC编程最基础的十大知识点详解

    这篇文章其实是学习PLC自动化过程中必须要理解的基础问题,不管是西门子PLC还是三菱PLC,抑或欧姆龙PLC,以及国产品牌的PLC,这些问题都必须理解透,才能更好的开始自动化编程.不然指令学完了梯形图 ...

  8. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  9. Pandas知识点-详解行列级批处理函数apply

    Pandas知识点-详解行列级批处理函数apply 在Pandas中,DataFrame和Series等对象需要执行批量处理操作时,可以借用apply()函数来实现. apply()的核心功能是实现& ...

最新文章

  1. 为何IDEA比Eclipse更好!
  2. 解决Word 2013, Word 2016的保存太慢的问题
  3. 一加3t刷机后还卡_一加8T/8/8Pro 氢OS11刷入面具magisk完美root权限超简单教程
  4. sql 判断某表是否存在
  5. Hello RoboCupRescue(RCR)
  6. 怎样学习和阅读技术书籍?
  7. TortoiseGit 下载、安装、配置_入门试炼_01
  8. php js脚本查询php,php结合js实现多条件组合查询
  9. vuex状态持久化_Vuex持久化存储之vuex-persist
  10. (c语言编程)出现错误:null undeclared identifier
  11. MongoDB复制集搭建主服务器模拟切换
  12. MySQL高可用性分析
  13. Vue学习笔记(利用网易云API实现音乐播放器 实例)
  14. ONES X 中农网|多产品线研发项目管理实践
  15. MySQL闪退解决办法
  16. 跟着小皮老师了解Go语言LiteIDE详细使用教程❤
  17. 查找文件命令find和文件内容查找命令grep
  18. fine-grained prosody control专栏
  19. 中国富豪掘第一桶金的九大方式
  20. 20、ZigBee 开发教程之基础篇—HC-SR501 人体红外传感器

热门文章

  1. AI看脸、测肤,左可美妆新零售,右能智慧医美
  2. matlab公共函数之保存YUV数据
  3. sshd_config配置详解
  4. 深入Android 【五】 —— 任务和进程
  5. 陈丕宏:公司领导人对企业文化的影响
  6. CodeForces - 1516D Cut(思维+倍增)
  7. HDU多校10 - 6880 Permutation Counting(dp+思维)
  8. ZOJ - 4117 BaoBao Loves Reading(树状数组求区间内不同数的个数+思维)
  9. CodeForces - 892E Envy(可撤销并查集)
  10. HDU - 3966 Aragorn's Story(树链剖分+线段树)