转 https://www.sohu.com/a/323031234_120104204
https://zhuanlan.zhihu.com/p/69114539
1 为什么需要 Zookeeper
很多中间件,比如Kafka、Hadoop、HBase,都用到了 Zookeeper,于是很多人就会去了解这个 Zookeeper 到底是什么,为什么它在分布式系统里有着如此无可替代的地位。
其实学任何一项技术,首先都要弄明白,为什么需要这项技术。
为什么需要 Zookeeper
正经点来回答,就是我们需要一个用起来像单机但是又比单机更可靠的东西。
下面开始不正经的回答。
一个团队里面,需要一个leader,leader是干嘛用的?管理什么的咱不说,就说如果外面的人,想问关于这个团队的一切事情,首先就会去找这个leader,因为他知道的最多,而且他的回答最靠谱。
比如产品经理小饼过来要人,作为leader,老吕发现小耀最近没有项目安排,于是把小耀安排给了小饼的项目;
过了一会,另一个产品小西也过来要人,老吕发现刚刚把小耀安排走了,已经没人,于是就跟小西说,人都被你们产品要走了,你们产品自己去协调去。
如果老吕这时候忘了小耀已经被安排走了,把小耀也分配给小西,那到时两个产品就要打架了。
这就是leader在团队里的协调作用。
同样的,在分布式系统中,也需要这样的协调者,来回答系统下各个节点的提问。
比如我们搭建了一个数据库集群,里面有一个Master,多个Slave,Master负责写,Slave只读,我们需要一个系统,来告诉客户端,哪个是Master。
有人说,很简单,我们把这个信息写到一个Java服务器的内存就好了,用一个map,key:master,value:master机器对应的ip
但是别忘了,这是个单机,一旦这个机器挂了,就完蛋了,客户端将无法知道到底哪个是Master。
于是开始进行拓展,拓展成三台服务器的集群。
这下问题来了,如果我在其中一台机器修改了Master的ip,数据还没同步到其他两台,这时候客户端过来查询,如果查询走的是另外两台还没有同步到的机器,就会拿到旧的数据,往已经不是master的机器写数据。
所以我们需要这个存储master信息的服务器集群,做到当信息还没同步完成时,不对外提供服务,阻塞住查询请求,等待信息同步完成,再给查询请求返回信息。
这样一来,请求就会变慢,变慢的时间取决于什么时候这个集群认为数据同步完成了。
假设这个数据同步时间无限短,比如是1微妙,可以忽略不计,那么其实这个分布式系统,就和我们之前单机的系统一样,既可以保证数据的一致,又让外界感知不到请求阻塞,同时,又不会有SPOF(Single Point of Failure)的风险,即不会因为一台机器的宕机,导致整个系统不可用。
这样的系统,就叫分布式协调系统。谁能把这个数据同步的时间压缩的更短,谁的请求响应就更快,谁就更出色,Zookeeper就是其中的佼佼者。
它用起来像单机一样,能够提供数据强一致性,但是其实背后是多台机器构成的集群,不会有SPOF。
讲完了上面这些,现在再来看官网这句话,就很能理解了:
ZooKeeper: A Distributed Coordination Service for Distributed Applications
当然还有这句:
而以往的很多ZK教程,上来就是“Zookeeper是开源的分布式应用协调系统”blabla,很多像我这样的小年轻看到就会很费解,到底什么是分布式协调,为什么分布式就需要协调 …
上面只是回答了我自己提出的问题,为什么需要Zookeeper,或者说,为什么需要分布式协调系统,如果想进一步学习 ZK,你还需要了解下 Zookeeper 的内部实现原理。
2 Zookeeper简介
Zookeeper是一个开源的分布式协调服务,目前由Apache进行维护。Zookeeper可以用于实现分布式系统中常见的发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。它具有以下特性:
- 顺序一致性 :从一个客户端发起的事务请求,最终都会严格按照其发起顺序被应用到Zookeeper中;
- 原子性 :所有事务请求的处理结果在整个集群中所有机器上都是一致的;不存在部分机器应用了该事务,而另一部分没有应用的情况;
- 单一视图 :所有客户端看到的服务端数据模型都是一致的;
- 可靠性 :一旦服务端成功应用了一个事务,则其引起的改变会一直保留,直到被另外一个事务所更改;
- 实时性 :一旦一个事务被成功应用后,Zookeeper可以保证客户端立即可以读取到这个事务变更后的最新状态的数据。
3 Zookeeper设计目标
Zookeeper致力于为那些高吞吐的大型分布式系统提供一个高性能、高可用、且具有严格顺序访问控制能力的分布式协调服务。它具有以下四个目标
3.1 目标一:简单的数据模型
Zookeeper通过树形结构来存储数据,它由一系列被称为ZNode的数据节点组成,类似于常见的文件系统。不过和常见的文件系统不同,Zookeeper将数据全量存储在内存中,以此来实现高吞吐,减少访问延迟。
3.2 目标二:构建集群
可以由一组Zookeeper服务构成Zookeeper集群,集群中每台机器都会单独在内存中维护自身的状态,并且每台机器之间都保持着通讯,只要集群中有半数机器能够正常工作,那么整个集群就可以正常提供服务。
3.3 目标三:顺序访问
对于来自客户端的每个更新请求,Zookeeper都会分配一个全局唯一的递增ID,这个ID反映了所有事务请求的先后顺序。
3.4 目标四:高性能高可用
ZooKeeper将数据存全量储在内存中以保持高性能,并通过服务集群来实现高可用,由于Zookeeper的所有更新和删除都是基于事务的,所以其在读多写少的应用场景中有着很高的性能表现。
4 核心概念
4.1 集群角色
Zookeeper集群中的机器分为以下三种角色:
1)Leader :为客户端提供读写服务,并维护集群状态,它是由集群选举所产生的;
2)Follower :为客户端提供读写服务,并定期向Leader汇报自己的节点状态。同时也参与写操作“过半写成功”的策略和Leader的选举;
3)Observer :为客户端提供读写服务,并定期向Leader汇报自己的节点状态,但不参与写操作“过半写成功”的策略和Leader的选举,因此Observer可以在不影响写性能的情况下提升集群的读性能。
4.2 会话
Zookeeper客户端通过TCP长连接连接到服务集群,会话(Session)从第一次连接开始就已经建立,之后通过心跳检测机制来保持有效的会话状态。通过这个连接,客户端可以发送请求并接收响应,同时也可以接收到Watch事件的通知。
关于会话中另外一个核心的概念是sessionTimeOut(会话超时时间),当由于网络故障或者客户端主动断开等原因,导致连接断开,此时只要在会话超时时间之内重新建立连接,则之前创建的会话依然有效。
4.3 数据节点
Zookeeper数据模型是由一系列基本数据单元 Znode (数据节点)组成的节点树,其中根节点为 / 。每个节点上都会保存自己的数据和节点信息。Zookeeper中节点可以分为两大类:
- 持久节点 :节点一旦创建,除非被主动删除,否则一直存在;
- 临时节点 :一旦创建该节点的客户端会话失效,则所有该客户端创建的临时节点都会被删除。
临时节点和持久节点都可以添加一个特殊的属性: SEQUENTIAL ,代表该节点是否具有递增属性。如果指定该属性,那么在这个节点创建时,Zookeeper会自动在其节点名称后面追加一个由父节点维护的递增数字。
4.4 节点信息
每个ZNode节点在存储数据的同时,都会维护一个叫做 Stat 的数据结构,里面存储了关于该节点的全部状态信息。如下:
4.5 Watcher
Zookeeper中一个常用的功能是Watcher(事件监听器),它允许用户在指定节点上针对感兴趣的事件注册监听,当事件发生时,监听器会被触发,并将事件信息推送到客户端。
该机制是Zookeeper实现分布式协调服务的重要特性。
4.6 ACL
Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,类似于UNIX文件系统的权限控制。它定义了如下五种权限
1)CREATE :允许创建子节点;
2)READ :允许从节点获取数据并列出其子节点;
3)WRITE :允许为节点设置数据;
4)DELETE :允许删除子节点;
5)ADMIN :允许为节点设置权限。
5 ZAB协议
5.1 ZAB协议与数据一致性
ZAB协议是Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。通过该协议,Zookeepe基于主从模式的系统架构来保持集群中各个副本之间数据的一致性。具体如下:
Zookeeper使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用原子广播协议将数据状态的变更以事务Proposal的形式广播到所有的副本进程上去。如下图:
具体流程如下:
所有的事务请求必须由唯一的Leader服务来处理,Leader服务将事务请求转换为事务Proposal,并将该Proposal分发给集群中所有的Follower服务。如果有半数的Follower服务进行了正确的反馈,那么Leader就会再次向所有的Follower发出Commit消息,要求将前一个Proposal进行提交。
5.2 ZAB协议的内容
ZAB协议包括两种基本的模式,分别是崩溃恢复和消息广播
1)崩溃恢复
当整个服务框架在启动过程中,或者当Leader服务器出现异常时,ZAB协议就会进入恢复模式,通过过半选举机制产生新的Leader,之后其他机器将从新的Leader上同步状态,当有过半机器完成状态同步后,就退出恢复模式,进入消息广播模式。
2) 消息广播
ZAB协议的消息广播过程使用的是原子广播协议。在整个消息的广播过程中,Leader服务器会为每个事务请求生成对应的Proposal,并为其分配一个全局唯一的递增的事务ID(ZXID),之后再对其进行广播。具体过程如下:
Leader服务会为每一个Follower服务器分配一个单独的队列,然后将事务Proposal依次放入队列中,并根据FIFO(先进先出)的策略进行消息发送。Follower服务在接收到Proposal后,会将其以事务日志的形式写入本地磁盘中,并在写入成功后反馈给Leader一个Ack响应。当Leader接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的Follower以通知其进行事务提交,之后Leader自身也会完成对事务的提交。而每一个Follower则在接收到Commit消息后,完成事务的提交。
6 Zookeeper的典型应用场景
6.1数据的发布/订阅
数据的发布/订阅系统,通常也用作配置中心。在分布式系统中,你可能有成千上万个服务节点,如果想要对所有服务的某项配置进行更改,由于数据节点过多,你不可逐台进行修改,而应该在设计时采用统一的配置中心。之后发布者只需要将新的配置发送到配置中心,所有服务节点即可自动下载并进行更新,从而实现配置的集中管理和动态更新。
Zookeeper通过Watcher机制可以实现数据的发布和订阅。分布式系统的所有的服务节点可以对某个ZNode注册监听,之后只需要将新的配置写入该ZNode,所有服务节点都会收到该事件。
6.2 命名服务
在分布式系统中,通常需要一个全局唯一的名字,如生成全局唯一的订单号等,Zookeeper可以通过顺序节点的特性来生成全局唯一ID,从而可以对分布式系统提供命名服务。
6.3 Master选举
分布式系统一个重要的模式就是主从模式(Master/Salves),Zookeeper可以用于该模式下的Matser选举。可以让所有服务节点去竞争性地创建同一个ZNode,由于Zookeeper不能有路径相同的ZNode,必然只有一个服务节点能够创建成功,这样该服务节点就可以成为Master节点。
6.4 分布式锁
可以通过Zookeeper的临时节点和Watcher机制来实现分布式锁,这里以排它锁为例进行说明:
分布式系统的所有服务节点可以竞争性地去创建同一个临时ZNode,由于Zookeeper不能有路径相同的ZNode,必然只有一个服务节点能够创建成功,此时可以认为该节点获得了锁。其他没有获得锁的服务节点通过在该ZNode上注册监听,从而当锁释放时再去竞争获得锁。锁的释放情况有以下两种:
- 当正常执行完业务逻辑后,客户端主动将临时ZNode删除,此时锁被释放;
- 当获得锁的客户端发生宕机时,临时ZNode会被自动删除,此时认为锁已经释放。
当锁被释放后,其他服务节点则再次去竞争性地进行创建,但每次都只有一个服务节点能够获取到锁,这就是排他锁。
6.5 集群管理
Zookeeper还能解决大多数分布式系统中的问题:
- 如可以通过创建临时节点来建立心跳检测机制。如果分布式系统的某个服务节点宕机了,则其持有的会话会超时,此时该临时节点会被删除,相应的监听事件就会被触发。
- 分布式系统的每个服务节点还可以将自己的节点状态写入临时节点,从而完成状态报告或节点工作进度汇报。
- 通过数据的订阅和发布功能,Zookeeper还能对分布式系统进行模块的解耦和任务的调度。
- 通过监听机制,还能对分布式系统的服务节点进行动态上下线,从而实现服务的动态扩容。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?