zookeeper

1.1 初识zookeeper

ZooKeeper是源代码开放的分布式协调服务,由雅虎创建,是Google Chubby的开源实现.ZooKeeper是一个高性能的分布式数据一致性解决方案,它将那些复杂的、容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并提供一系列简单易用的接口给用户使用.

zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、master选举、分布式锁和分布式队列等.

zookeeper可以保证如下分布式一致性特性

  • 顺序一致性:从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到Zookeeper中
  • 原子性:所有事务的请求结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么在整个集群中所有机器上都成功应用了某一个事务,要么都没有应用,没有中间状态
  • 单一视图:无论客户端连接的是哪个Zookeeper服务器,其看到的服务端数据模型都是一致的
  • 可靠性:一旦服务端成功应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来,除非有另一个事务又对其进行了变更
  • 实时性:Zookeeper仅仅保证在一定的时间内,客户端最终一定能够从服务端上读到最新的数据状态

1.2 设计目标

ZooKeeper致力于提供一个高性能、高可用,具有严格顺序访问控制能力(主要是写操作的严格顺序性)的分布式协调服务.

设计目标

  • 简单的数据模型:Zookeeper使得分布式程序能够通过一个共享的,树型结构的名字空间进行相互协调.Zookeeper将全量数据存储在内存中,以此来实现提高服务器吞吐,减少延迟的目的
    • 可以构建集群:一个ZooKeeper集群通常由一组机器组成,一般3~5台机器就可以组成一个可用的ZooKeeper集群,每台机器之间都互相保持着通信.只要集群中存在超过一半的机器能够正常工作,那么整个集群就能够正常对外服务.Zookeeper的客户端程序会选择和集群中任意一台机器共同来创建一个TCP连接,而一旦客户端和某台Zookeeper服务器之间的链接断开后,客户端会自动链接到集群中的其他机器
  • 顺序访问:对于来自客户端的每个更新请求,Zookeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序,应用程序都可以使用ZooKeeper的这个特性来实现更高层次的同步原语
    • 高性能:ZooKeeper将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,因此它尤其适用于以读操作为主的应用场景

1.3 基本概念

1.3.1 集群角色

在ZooKeeper中,没有沿用传统的Master/Slave概念,而是引入Leader,Follower和Observer三种角色.ZooKeeper集群中的所有机器通过一个Leader选举过程来选定一台被称为“Leader”的机器,Leader服务器为客户端提供读和写服务.除Leader外,其他机器包括Follower和Observer都能够提供读服务,唯一的区别在于,Observer机器不参与Leader选举过程,也不参与写操作的“过半写成功”策略.因此Observer可以在不影响写性能的情况下提升集群的读性能.

1.3.2 会话(Session)

会话是指客户端和ZooKeeper服务器的连接.客户端与服务器建立一个TCP的长连接来维持一个Session,客户端在启动的时候首先会与服务器建立一个TCP连接,通过这个连接,客户端能够通过心跳检测与服务器保持有效会话,也能向ZK集群服务器发送请求并获得响应,同时还能够通过该链接接受来自服务器的Watch事件通知.

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

1.3.3 数据节点(Znode)

ZooKeeper集群

  • 机器节点:集群中的一台机器称之为一个节点
  • 数据节点:数据模型中的数据单元Znode.数据模型是一棵树(Znode Tree),由斜杠/进行分割的路径,就是一个ZNode.每个ZNode都会保存自己的数据内存,同时还会保存一些列属性信息

    ZNode

  • 持久节点: 一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上
  • 临时节点: 生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除

    Zookeeper还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL.一旦节点被标记上这个属性,那么在这个节点被创建的时候,Zookeeper会自动在其节点后面追加一个整形数字,其是由父节点维护的自增数字.

1.3.4 版本

对于ZNode,Zookeeper都会为其维护一个叫做Stat的数据结构,Stat中记录了这个ZNode的三个数据版本

  • version: 当前ZNode的版本号
  • cversion: 当前ZNode子节点的版本号
  • aversion: 当前数ZNode的ACL版本号

可以利用版本来实现分布式的锁服务

1.3.5 Watcher

事件监听器,Zookeeper集群允许用户在指定的节点上注册Watcher(事件监听器),并在一些特定事件出发的时候,Zookeeper服务器会把这个变化的通知发送给感兴趣的客户端.客户端收到这个变化通知,可以再回到Zookeeper中去取得数据的详细信息.

1.3.6 ACL权限控制

ACL是Access Control Lists的简写,Zookeeper采用ACL策略来进行权限控制.

ACL拥有以下五种权限类型

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

2.ZAB

2.2.1 ZAB协议

Zookeeper使用了Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法.ZAB协议是为Zookeeper专门设计的一种支持崩溃恢复的原子广播协议.

Zookeeper依赖ZAB协议来实现分布式数据的一致性,基于该协议,Zookeeper实现了一种主备模式的系统架构来保持集群中各副本之间的数据的一致性,即其使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以事务Proposal的形式广播到所有的副本进程中,ZAB协议的主备模型架构保证了同一时刻集群中只能够有一个主进程来广播服务器的状态变更,因此能够很好地处理客户端大量的并发请求.

ZAB协议的核心是定义了对于那些会改变Zookeeper服务器数据状态的事务请求的处理方式,即:所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为Leader服务器,余下的服务器则称为Follower服务器,Leader服务器负责将一个客户端事务请求转化成一个事务Proposal(提议),并将该Proposal分发给集群中所有的Follower服务器,之后Leader服务器需要等待所有Follower服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,那么Leader就会再次向所有的Follower服务器分发Commit消息,要求其将前一个Proposal进行提交.

2.2.2 ZAB协议介绍

ZAB两种基本的模式:崩溃恢复和消息广播.

崩溃恢复 当整个服务框架启动过程中或Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader服务器.

当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式,那么整个服务框架就可以进入消息广播模式.

Leader选举算法不仅仅需要让Leader自身知道已经被选举为Leader,同时还需要让集群中的所有其他机器也能够快速地感知到选举产生的新的Leader服务器.

当Leader服务器出现崩溃或者机器重启、集群中已经不存在过半的服务器与Leader服务器保持正常通信时,那么在重新开始新的一轮的原子广播事务操作之前,所有进程首先会使用崩溃恢复协议来使彼此到达一致状态,于是整个ZAB流程就会从消息广播模式进入到崩溃恢复模式.

消息广播 ZAB协议的消息广播过程使用原子广播协议,类似于一个二阶段提交过程,针对客户端的事务请求,Leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交.

ZAB协议-消息广播

整个消息广播协议是基于具有FIFO特性的TCP协议来进行网络通信的,因此能够很容易保证消息广播过程中消息接受与发送的顺序性.

整个消息广播过程中,Leader服务器会为每个事务请求生成对应的Proposal来进行广播,并且在广播事务Proposal之前,Leader服务器会首先为这个事务Proposal分配一个全局单调递增的唯一ID,称之为事务ID(ZXID),由于ZAB协议需要保证每个消息严格的因果关系,因此必须将每个事务Proposal按照其ZXID的先后顺序来进行排序和处理.

当一台同样遵守ZAB协议的服务器启动后加入到集群中,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去.

基本特性

  • ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交.
  • ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务

ZAB协议规定了如果一个事务Proposal在一台机器上被处理成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障崩溃.

Leader选举算法 能够确保提交已经被Leader提交的事务的Proposal,同时丢弃已经被跳过的事务Proposal.如果让Leader选举算法能够保证新选举出来的Leader服务器拥有集群中所有机器最高编号(ZXID最大)的事务Proposal,那么就可以保证这个新选举出来的Leader一定具有所有已经提交的提议,更为重要的是如果让具有最高编号事务的Proposal机器称为Leader,就可以省去Leader服务器查询Proposal的提交和丢弃工作这一步骤了.

数据同步 完成Leader选举后,在正式开始工作前,Leader服务器首先会确认日志中的所有Proposal是否都已经被集群中的过半机器提交了,即是否完成了数据同步.

下面分析ZAB协议如何处理需要丢弃的事务Proposal的,ZXID是一个64位的数字,其中低32位可以看做是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal时,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举产生一个新的Leader时,就会从这个Leader上取出其本地日志中最大事务Proposal的ZXID,并解析出epoch[‘ɛpək]值,然后加1,之后以该编号作为新的epoch,低32位从0来开始生成新的ZXID,ZAB协议通过epoch号来区分Leader周期变化的策略,能够有效地避免不同的Leader服务器错误地使用不同的ZXID编号提出不一样的事务Proposal的异常情况.当一个包含了上一个Leader周期中尚未提交过的事务Proposal的服务器启动时,其肯定无法成为Leader,因为当前集群中一定包含了一个Quorum(过半)集合,该集合中的机器一定包含了更高epoch的事务的Proposal,因此这台机器的事务Proposal并非最高,也就无法成为Leader.

ZAB协议

ZAB协议算法描述

  • CEPOCH: Follower进程向准Leader发送自己处理过的最后一个事务Proposal的epoch值
  • NEWEPOCH: 准Leader进程根据接收的各进程的epoch, 来生成新一轮周期的epoch值
  • ACK-E: Follower进程反馈准Leader进程发来的NEWEPOCH消息
  • NEWlEADER: 准Leader进程确立自己的领导地位,并发送NEWLEADER消息给各进程
  • ACK-LD: Follower进程反馈Leader进程发来的NEWlEADER消息
  • COMMIT-LD: 要求Follower进程提交相应的历史事务Proposal
  • PROPOSE: Leader进程生成一个针对客户端事务请求的Proposal
  • ACK: Follower进程反馈Leader进程发来的PROPOSAL消息
  • COMMIT: Leader发送COMMIT消息,要求所有进程提交事务PROPOSE

2.3ZAB协议原理

ZAB主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是发现(Discovery)、同步(Synchronization)、广播(Broadcast)阶段.ZAB的每一个分布式进程会循环执行这三个阶段,称为主进程周期.

  • 发现,选举产生PL(prospective leader),PL收集Follower epoch(cepoch),根据Follower的反馈,PL产生newepoch(每次选举产生新Leader的同时产生新epoch).
  • 同步,PL补齐相比Follower多数派缺失的状态、之后各Follower再补齐相比PL缺失的状态,PL和Follower完成状态同步后PL变为正式Leader(established leader).
  • 广播,Leader处理客户端的写操作,并将状态变更广播至Follower,Follower多数派通过之后Leader发起将状态变更落地(deliver/commit).

在正常运行过程中,ZAB协议会一直运行于阶段三来反复进行消息广播流程,如果出现崩溃或其他原因导致Leader缺失,那么此时ZAB协议会再次进入发现阶段,选举新的Leader.

每个进程都有可能处于如下三种状态之一

  • LOOKING: Leader选举阶段.
  • FOLLOWING: Follower服务器和Leader服务器保持同步状态.
  • LEADING: Leader服务器作为主进程领导状态.

一个Follower只能和一个Leader保持同步,Leader进程和所有与所有的Follower进程之间都通过心跳检测机制来感知彼此的情况.若Leader能够在超时时间内正常收到心跳检测,那么Follower就会一直与该Leader保持连接,而如果在指定时间内Leader无法从过半的Follower进程那里接收到心跳检测,或者TCP连接断开,那么Leader会放弃当前周期的领导,转换到LOOKING状态.

2.4 ZAB与Paxos的联系和区别

联系:

  • 都存在一个类似于Leader进程的角色,由其负责协调多个Follower进程的运行.
  • Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提议进行提交.
  • 在ZAB协议中,每个Proposal中都包含了一个epoch值,用来代表当前的Leader周期,在Paxos算法中,同样存在这样的一个标识,名字为Ballot.

区别:

  • Paxos算法中,新选举产生的主进程会进行两个阶段的工作,第一阶段称为读阶段,新的主进程和其他进程通信来收集主进程提出的提议,并将它们提交.第二阶段称为写阶段,当前主进程开始提出自己的提议.
  • ZAB协议在Paxos基础上添加了同步阶段,此时,新的Leader会确保存在过半的Follower已经提交了之前的Leader周期中的所有事务Proposal.
  • ZAB协议主要用于构建一个高可用的分布式数据主备系统,而Paxos算法则用于构建一个分布式的一致性状态机系统.

results matching ""

    No results matching ""