大数据理论与实践2 分布式协调服务Zookeeper

分布式系统

  • 将硬件或软件组件(服务)分布在不同的网络计算机上
  • 通过消息传递进行通信和协调

特点

  • 分布性
  • 对等性:平等(无主从之分);独立(拥有自己的CPU和内存,独立处理数据)
  • 并发性:内部(作业(Job)被分解成多个任务(Task),并发运行在不同的节点上);外部(承载多个客户端的并发访问)
  • 故障独立性:部分节点出现故障不影响整个系统的正常使用

典型的问题

  1. 通信异常
  2. 网络分区(脑裂):系统分裂为两个甚至多个局部小集群(分区);各分区独立运行,同时提供服务,从而导致混乱
  3. 节点故障:宕机或僵死
  4. 三态:成功、失败和超时

CAP定理

什么是CAP

  1. C(Consistency,一致性)
  • 含义:同一时刻,数据在不同节点的多个副本是否具有完全相同的值
  • 类型
    • 强一致性:数据更新完成后,同一时刻,不同的读操作都能获得最新的值
    • 弱一致性:数据更新完成后,同一时刻,不同的读操作不一定都能获得最
      新的值,也无法保证多长时间之后可以获得最新的值
  1. A(Availability,可用性)
    含义:对于每一次请求,系统是否都能在有限(指定)的时间内做出响应
  2. P(Partition Tolerance,分区容错性,最重要)
    含义:当发生网络分区时,系统仍能对外提供满足一致性C和可用性A的服务

CAP定理内容

表述:分布式系统在同一时间片段内,不可能同时满足一致性C(此处指强一致性)、可用性A和分区容错性P,最多只能满足其中的两项。
注意:“满足”意味着100%,C满足强一致性,A 满足绝对可用性。
对分布式系统而言,网络分区无法避免,满足P是前提条件,所以不可能选CA架构,只能选择CP或AP架构。
举例:发生网络分区时,某个节点正在进行写操作:
如果为了保证C,必须禁止其他节点的读写操作,那就与A冲突了;
如果为了保证A,其他节点正常读写,那就与C冲突了。
CAP是一种比较脱离实际的理想化的内容。

BASE理论

什么是BASE

  1. BA(Basically Availability,基本可用性)
    当系统发生故障时,在确保核心功能和指标有效的提前下,允许损失部分可用性,包括响应时间上的损失、非核心功能上的损失等.
  2. S(Soft State,软状态)
  • 允许数据存在中间状态(暂时未更新),且该状态不会影响整体可用性
  • 允许不同节点上的数据副本的同步过程存在一定延时
  1. EC(Eventually Consistency,最终一致性)
    分布在不同节点上的数据副本,在经过一定时间的同步后,最终达到一致状态。例如:Zookeeper、HDFS QJM写事务的过半策略。
    可以理解为弱一致性的升级版,强一致的妥协版。

BASE理论内容

表述:分布式系统在满足分区容错性P的同时,允许数据软状态S的存在,并实现基本可用性BA和最终一致性EC。
理解:在满足P的前提下,对CAP中的强一致性A和绝对可用性C进行适度妥协。通过容忍部分数据的暂时不一致(软状态),即牺牲数据的强一致性(确保最终一致性),以确保系统的核心功能和指标有效(基本可用)。

ZooKeeper

什么是ZooKeeper

三高”:高可用高容错高性能的分布式协调系统。
将复杂易错的分布式一致性服务封装起来,形成高效可靠的原语集,并提供简单易用的访问接口。
为大型分布式系统提供关键、共性、高效和可靠的协调服务,包括:

  • 数据发布订阅
  • 分布式锁
  • 统一命名
  • 配置管理
  • 集群管理(Master选举、节点上下线动态监测)
    目前ZooKeeper是开源技术体系的无可替代基础组件

基本特性

  • 最终一致性(最重要的功能,实现BASE理论)
  • 有限实时性(不能保证拿到最新数据)
  • 原子性(集群所有服务器都成功执行了某一事务,或者都没有)
  • 顺序性(事务严格按照顺序应用到ZooKeeper)
  • 可靠性(服务器执行了某一事务,引起的数据改变要保留)
  • 单一视图(无论连接哪个服务器,看到的数据模型都是一致的)

ZooKeeper原理

这一模块主要涉及系统架构、数据模型、数据读写、Leader选举、Watcher机制。

系统架构

Master/Slave架构

角 色职 责
Leader(领导者 / Master / 集群中唯一)接收Follower和Observer转发的写请求;事务的发起和决议;更新系统状态
Leaner(学习者 / Slave)Follower(跟随者)处理客户端读请求,将写请求转发给Leader;参与Leader发起的事务处理,负责本节点的数据变更和事务提交;参与Leader选举;同步Leader状态(保持心跳连接)
Observer(观察者)处理客户端读请求,将写请求转发给Leader ;不参与Leader发起的事务处理;不参与Leader选举 ;同步Leader状态(保持心跳连接)
Client(客户端)发起读写请求

Leader和Follower遵循“Quorum仲裁机制(过半策略)”,参与事务处理和Leader选举的投票:若Leader+Follwer的数量为m,则Quorum = m/2 + 1,只有投票数大于等于Quorum,事务和选举才判定成功。
例如上图三个Leader和Follower,则Quorum=2,投票数大于等于2,事务和选举判定成功。
Leader+Follower最好是奇数,这样的话在不影响事务处理的前提下,最多可容忍n台宕机。
举例:对于节点数为5和6的两个集群:

  1. 二者都最多容忍2台宕机,所以容灾能力相同;
  2. 前者的Quorum数为3,后者为4,前者更小,事务处理和选举的效率更高

为什么要引入Observer(ZK 3.3.0)?

  1. 在不影响写性能的前提下,提升读操作的性能和吞吐量
    ① Follower数量越多,写操作的性能越差,吞吐量越小
    ② Observer不参与事务处理,数量再多也不影响集群的写性能
    ③ Observer不参与选主和事务处理,即使宕机也不影响集群的可用性

  2. 提升集群的可扩展性,以及大规模访问的承载能力

  3. 跨中心部署Observer ,为本地读请求提供快速响应
    ① Leader和Follower部署在一个中心,很大程度上降低了网络延时对写性能的影响
    ②由于Observer要转发写请求和同步Leader状态,所以跨中心部署并不能彻底消除网络延时
    例如:阿里开源的跨机房同步系统Otter

数据模型 Znode

Znode是Zookeeper的最小数据单元,节点有数据存储功能(非数据库),大小不能超过1M,节点中的数据应尽可能小,数据过大会导致ZK性能明显下降。如果确实要存储较大的数据,可将其放在数据库中,而存储地址放在Znode中(以HBase为例,元数据放在RegionServer中,元数据的寻址入口放在ZK中)。

Znode Tree是Znode通过挂载子节点而形成的一个树状层次化命名空间,结构类似于Linux文件系统,但没有目录和文件,只有节点和子节点。绝对路径(非相对路径)作为节点名称,用于唯一标识节点;根节点为“/”,非根节点为不能以“/”结尾
在这里插入图片描述
会话(Session):是客户端为实现Znode读写操作与ZK服务器建立的TCP长连接,即会话。在SessionTimeout时间内,客户端会通过心跳检测(Ping)或发送读写请求来激活和保持会话,但服务器要是一直未收到客户端消息,就会判定超时并关闭会话;在某一会话中,客户端请求以FIFO方式顺序执行。

Znode节点类型
  1. 持久节点(PERSISTENT)
    节点默认类型,生命周期不依赖于客户端会话,只有客户端执行删除操作时,节点才会消失。
    可以拥有子节点,也可以是叶节点。
  2. 临时节点(EPHEMERAL)
    生命周期依赖于客户端会话,当会话结束时,节点会自动删除(也可手动删除)。
    不能拥有子节点,只能是叶节点(删除节点后子节点也会删除,因此临时节点作为父节点没有必要)。
  3. 顺序节点(SEQUENTIAL)
    带顺序编号的持久或临时节点
    创建顺序节点时,在路径后面会自动添加一个10位的节点编号(计数器),如 < path1>0000000001, < path2>0000000002,…,该编号在同一父节点下是唯一的。
Znode版本

Znode版本是形如0,1,2,…,N的单调递增数字,不是形如v1.2.1的软件版本,其中包括了:

  • dataVersion(数据版本,只要发生了数据更新就自增1)
  • cVersion(子节点版本,只要子节点发生了变化就自增1)
  • aclVersion(Access Control List, 访问控制列表发生变更时自增1)
    作用:利用版本为分布式事务操作的确保原子性
    悲观锁:事务A执行期间,数据全程加锁,其他事务只能等待;适用于数据更新并发度较高的场景
    乐观锁:事务A提交更新请求前,先检查数据是否被其他事务修改过(通过比较版本进行写入校验),如修改过,则相关事务必须回滚;适用于数据更新并发度不高的场景。
    乐观锁的例子:
    在这里插入图片描述
  1. 事务A向ZooKeeper发起确认:dataversion是否等于1
  2. ZooKeeper确认dataversion是1,在数据更新后,返回dataversion是2
  3. 此时事务B到来,获取了dataversion,并且进行了数据更新,dataversion变成了3
  4. 此时事务A继续处理,向ZooKeeper发起确认dataversion是否为2
  5. ZooKeeper返回版本错误,事务A就此fail

数据读写

ZAB协议

Zookeeper Atomic BroadcastZooKeeper原子广播协议,是BASE理论的具体实现,是Paxos 算法的变种实现。基于该协议,ZK实现了Master/Slave架构下集群各节点副本数据的最终一致性
主要通过实现两种模式:正常运行时的消息广播模式、Leader故障时的崩溃恢复模式
数据写入
在这里插入图片描述

  1. Follwer接收客户端写请求,并将其转发给Leader
  2. Leader接收写请求,为其分配一个全局唯一的事务ID,Zxid(64位/单调递增)
  3. Leader生成一个形如(Zxid, data)的事务提案Proposal(data是事务体),并将其放入各Follower对应的FIFO队列中(通过TCP协议实现),再按照FIFO策略把Proposal广播出去
  4. Follower接收Proposal后,先以事务日志的形式落盘,再向Leader发送ack
  5. 当Leader接收到超过半数的ack之后(包括Leader自己),会向Follower发送commit命令,要求提交事务,同时自己在本地commit
  6. Follower收到commit命令后提交事务,同时向客户端反馈结果
    在这里插入图片描述

拿现实生活举例子:银行

  1. 客户①找到柜员①,说:昨天少给我存了1000,现在要加回来
  2. 柜员①说:对不起先生,我没权决定,请稍等,向领导柜员③汇报一下
  3. 柜员③收到消息后,经查账发现是搞错了,但按照规定必须向柜员①②④⑤征求意见(广播Proposal)
  4. 柜员①②反馈同意,柜员④⑤还在忙其他事情,但因为已经过半数的柜员(包括Leader)同意,所以Leader做出决定同意补钱(事务Commit)
  5. 柜员③告知所有下属,登记此事并生效
  6. 柜员①答复客户①,给您账号里加了1000

这里注意:只要有一个节点完成了commit,那么就可以告诉client事务完成。(只要有一个业务员完成登记,就可以告诉客户钱整好了)

数据恢复

  1. 当Leader无法提供服务时,快速选举出一个新Leader
  2. Follower与新Leader同步数据:原则上,对于某个事务,如果至少一个Follwer接收到Proposal并最终执行了commit,那么该事务数据就应该被永久保留

问题:如果Leader把某个Proposal广播给所有Follwer之后宕机,数据该怎么处理?
数据应该丢弃,因为该条数据并没有commit,不需要(没这个义务)进行保留。

数据读取
客户端直接从Follower或Observer读取数据,如果要确保读到最新数据,应该先调用sync()进行强制同步。

Leader选举

服务器的四种状态:

  • LOOKING:寻找Leader状态,表示当前集群没有Leader,需要进行选举
  • LEADING:领导者状态,当前角色为Leader
  • FOLLOWING:跟随者状态,Leader选举已完成,当前角色为Follower
  • OBSERVING:观察者状态,当前角色为Observer,不参与选举和写事务

选举的原则:选择能力强,数据新的节点作为Leader

启动期间的Leader选举

在这里插入图片描述
如上图所示,在启动时期Leader选举

  1. 启动ZK1并发起投票。投票(1,0)给自己,发现未过半数,选不出Leader
  • 选票的数据结构:(sid, zxid),sid为服务器id,zxid为当前服务器的最大事务id
  • 选票的比较规则: ①zxid大的胜出;②若zxid相等,则sid大的胜出
  1. 启动ZK2
    (1)发起第1轮投票。ZK1和ZK2分别投票给自己和其他服务器,ZK1为(1,0),ZK2为(2,0)
    (2)统计第1轮投票。ZK1对投给自己的票(1,0)与ZK2发过来的票(2,0)进行比较,根据比较规则,(2,0)胜出,ZK1更新自己的投票为(2,0);以此类推,ZK2保持自己的投票(2,0)不变。至此,ZK1和ZK2都给ZK2投了1票,但未过半数,选不出Leader
    (1)发起第2轮投票。 ZK1和ZK2分别投票给自己和其他服务器,ZK1为(2,0),ZK2为(2,0)
    (2)统计第2轮投票。 ZK1和ZK2都有2票(2,0),已超过半数,ZK2当选Leader
    (3)更改Server状态。将ZK2的状态改为LEADING,ZK1的状态改为FOLLOWING
  2. 启动ZK3。发现已有Leader,不再选举,直接从LOOKING改为FOLLOWING
运行期间的Leader选举

在这里插入图片描述
这里也贯穿着选举思想:能力强,数据新

Watcher机制

Watcher机制是观察者模式在分布式场景下的实现。

  1. 注册Watcher监听器:客户端向ZK的某个Znode注册一个Watcher监听器
  2. 存储Watcher对象:客户端把Watcher对象存储到本地的WatchManager中
  3. 处理Watcher事件:当服务端的指定事件触发了Watcher,会向客户端发送事件通知
  4. 回调Watcher对象:客户端根据通知状态和事件类型回调WatchManager中的Watcher对象,执行相应的业务逻辑

Watcher的特性:

  • 一次性:一旦触发就会被删除,再次使用时需重新注册
  • 轻量级:仅包含通知状态、事件类型和节点路径,不包含数据节点变化前后的具体内容
  • 时效性:Watcher只有在当前Session结束后才会失效;如果在Session有效期内快速重连成功,则Watcher依然有效,仍可接收到通知
  • 顺序回调:Watcher回调是顺序串行的;回调逻辑不应太多,以免影响其他Watcher执行;只有回调后客户端才能看到最新的数据状态

ZooKeeper应用场景

分布式锁

分布式锁实现1:竞争创建锁

依据:

  • 多个客户端同时创建同一个Znode节点(节点路径名唯一),只有一个客户端能够成功
  • Watcher机制
    在这里插入图片描述
    步骤
  1. 多个客户端同时在ZK上竞争创建临时节点“/Lock”(简称Lock节点) ,创建成功的客户端获得锁,并执行事务
  2. 其他客户端注册Watcher监听器,监听Lock节点
  3. 事务完成后,获得锁的客户端会删除Lock节点,释放锁,同时触Watcher,通知其他客户端
  4. 其他客户端再次竞争创建Lock节点

问题羊群效应:即当锁被释放后,如果抢占锁资源的竞争客户端太多,势必会影响性能。
羊群效应的理解:集群中的羊群效应

分布式锁实现2

依据:临时顺序节点 + Watcher机制
实现2
步骤:

  1. 客户端在永久节点“/Lock”下创建临时顺序子节点,第一个客户端创建的子节点为“/Lock/Lock-0”,第二个为“/Lock/Lock-1”,以此类推
  2. 客户端获取Lock节点的子节点列表,判断其创建的子节点的序号是否最小,如果是则获得锁,否则就监听序号排在其前一位的子节点
  3. 锁释放后,对应的子节点被删除,该节点序号后一位的子节点得到通知,重复步骤2直至获得锁

统一命名

ZooKeeper能够实现分布式的编号唯一,但是实战中并不推荐。

服务统一命名

类似于JNDI,记录域名与IP之间的对应关系,域名作为访问入口
按照Znode Tree层次结构组织服务名称

全局唯一ID

UUID虽然可以保证分布式环境下的编号唯一,但缺点是无序、存储空间大和查询效率低。利用Znode顺序节点,可以实现分布式环境下的编号生成(ID生成器)。

配置管理

集群中所有节点的配置信息需保持一致;当配置信息修改后,应快速同步到其他节点上。
Znode+Watcher实现统一配置管理:

  1. 将配置信息写入Znode
  2. 各节点监听Znode,一旦Znode的数据被修改,将通知各节点进行更新

集群管理

Znode+Watcher实现集群管理:
管理
将节点的状态信息写入Znode,利用Watcher监听Znode,以获取节点的实时状态变化。
节点上下线动态监测
新节点启动后,先在ZK中创建临时顺序Znode,这时会触发父节点上的监听器,并通知集群管理节点Master有新节点上线;
节点发生故障,失去与ZK的心跳连接,它创建的临时顺序Znode被自动删除,这时会触发父节点上的监听器,并通知Master节点下线
Master选举
如果Master节点宕机,失去与ZK的心跳连接,那么它创建的临时Znode被自动删除,这时会触发该节点的Watcher,并通知所有Standby节点去竞争创建临时Znode
成功创建临时Znode的Standby节点成为新的Master
其他Standby节点在该Znode上注册监听器,等待下一次选举

课后温习

为什么说BASE理论是CAP定理的延伸?
答:CAP是一种比较脱离实际的理论化、理想化的内容,要求在实现P的条件下完全满足A或完全满足C;BASE理论是一种具有可实践性的理论,核心思想是即使无法做到强一致性,但应用可以采用适合的方式达到最终一致性,是对C和A的一种权衡。

请简述ZAB协议的基本内容。
ZAB协议是ZooKeeper原子广播协议,是ZooKeeper实现数据最终一致性的算法,是BASE理论的具体实现。一般分布式系统中会采用主从架构,那么在主从架构中会出现两个问题:主如何把数据发给从;主出问题了怎么办。ZAB协议就是未来解决这两个问题的,采用的方法是消息广播模式(半数同意,事务commit)和崩溃恢复模式(选能力强数据新的作为新Leader)。

为什么ZK的Leader和Follower数量最好是奇数,而不是偶数?
对于2n-1和2n个数目的Leader+Follower,二者都最多容忍n台宕机,所以容灾能力相同;但是前者Quorum仲裁时需要n台机器投票,而后者需要n+1台机器投票,因此事务处理和选举的效率更高。

为什么要在ZK引入Observer这一角色?
主要与三点:性能提升,可扩展性,跨中心部署提升读效率。

请简述ZK数据写入的基本步骤。
六步:
Follower接受请求并转发给Leader→Leader为这个事务创建一个事务ID→Leader发送事务提案给Follower→Follower存储下提案并返回ack→收到超过半数的ack之后,给Follower发送commit命令→接受客户请求的Follower收到commit命令,返回给客户。

请简述ZK运行期间的Leader选举过程。
第一轮都把选票投给自己,选票的数据结构是(sid,zxid)
进行票数统计,在收到的选票中选择zxid最大的,如果多个zxid相同就选择sid大的
第二轮投票,把刚刚选择的选票广播出去
票数统计,如果能够选出Leader就完成选举,否则继续进行选举

如何利用临时顺序节点实现分布式锁?
首先,在永久节点下创建临时顺序子节点Lock0,Lock1等;然后,获取Lock节点的子节点列表,判断当前子节点的序号是否最小,如果是则获得锁,否则就监听序号排在其前一位的子节点;锁释放后,对应的子节点被删除,该节点序号后一位的子节点得到通知。

Reference

课程内容来自:南京大学+星环科技课程,大数据大数据理论与实践课程
CAP理论中的P到底是个什么意思?-四猿外

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值