Zookeeper学习笔记-基本概念及原理

一直以来都没有系统的学习过分布式相关框架,打算先从Zookeeper入手,接下来1个多月,准备阅读学习下《从paxos到Zookeeper分布式一致性原理与实践》这本书,并在Zookeeper学习笔记系列中记录下学习的一些关键点,期间也会做部分Zk相关应用实践并做分享,也欢迎各位看官指出不足之处。

本文将从以下几点来介绍Zookekper及其基本原理:

  • Zookeeper项目简介
  • Zookeeper有哪些功能
  • Zookeeper基本概念
  • 什么是Zab协议

一、Zookeeper项目简介

Apache Zookeeper是由Apache Hadoop子项目发展而来,于2010年11月正式成为了Apache顶级项目。Zookeeper是一个为分布式应用提供高效、可靠的一致性服务的基础服务。

二、Zookeeper有哪些功能

  • 配置管理
    Zookeeper本身可以当做分布式文件系统使用,服务配置可以以节点目录形式存储于Zookeeper中,相关应用程序对节点目录进行监听,在配置发生变化时,收到通知,并对应用程序做修改
  • 分布式锁
    如:N台服务应用需要抢占AccountService中的锁,则所有机器同时在/projectName/AccountService下创建临时顺序节点,节点编号最小的获取锁,节点顺序大的依次监听前面一个节点,待前节点释放删除后重新抢锁,流程图如下
    Zookeeper学习笔记-基本概念及原理
  • master选举
    原理同分布式锁实现中的临时顺序节点实现方案,在同一目录下创建临时节点,节点编号最小的为master
  • 服务发布/订阅
    项目中用到Zookeeper最多的地方可能就是dubbo里的注册中心,就是服务发布/订阅的一个例子。因为zookeeper是一个树形的目录服务,节点信息维护于内存中,支持变更推送(客户端机器与Zk节点维持Tcp长链接,接受变更推送),且稳定性,可用性高,故dubbo默认使用Zk作为注册中心。dubbo中服务注册订阅相关流程如下图所示:
    Zookeeper学习笔记-基本概念及原理
  1. 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址

  2. 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址

  3. 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址。

    简单点说,ZooKeeper = 文件系统 + 通知机制

三、Zookeeper基本概念

集群角色

  • Leader: 集群中所有机器通过Leader选举选定的一台机器即为Leader,提供读和写服务,所有zk事务操作均通过Leader发起,待Follower过半响应Ack后Commit事务确认事务成功
  • Follower: 提供读服务,参与Leader选举,参与过半写成功策略
  • Observer: 提供读服务,不参与Leader选举,不参与过半写成功,即Observer只提供读服务,可水平拓展Observer机器来提升Zk集群读性能

    用表格说明这几个角色的功能如下图:
是否提供读服务 是否参与Leader选举 是否参与事务过半写成功策略
Leader
Follower
Observer

通知机制(Watch)

客户端能够注册监听它所关心的节点信息,待节点信息发生变化(数据被修改、删除、子节点新增删除)时,客户端能够收到通知

数据节点(Znode)

Zookeeper将所有数据存储于内存中,数据结构是一颗树,由斜杠分割的一个路径,就是一个Znode。Znode包含数据信息以及一系列状态属性信息(如事务id,节点创建时间等),同时节点下还能挂载子节点,整体数据结构与文件系统非常类似。如上述dubbo例子中的/dubbo/com.foo.BarService/providers就是一个Znode。

Znode分为持久节点、临时节点
持久节点 - 一旦Znode被创建,除非手动删除,否则会常驻在Zookeeper内存中

临时节点 - 生命周期与会话绑定,一旦由于网络波动或者是zk服务器宕机导致客户端与zk服务器之间的Tcp长连接断开,都会导致节点被删除

节点的Sequential(有序)特性:Zookeeper允许用户为每个节点添加一个特殊有序属性,添加后,会自动在每个节点创建后在其名称后追加一个由父节点维护的自增数字,该特性导致持久节点和临时节点又可被细分为:

– 持久节点(PERSISTENT)
– 持久顺序节点(PERSISTENT_SEQUENTIAL)
– 临时节点(EPHEMERAL)
– 临时顺序节点(EPHEMERAL_SEQUENTIAL)

其中临时顺序节点在使用zookeeper做分布式锁的实现中有广泛使用,关于zookeeper实现的分布式锁,后续实战文章会做介绍

四、什么是Zab协议

Zab协议(全称Zookeeper atomic broadcast协议,即zk原子广播协议),支持崩溃恢复功能。基于该协议,Zookeeper实现了主备(Leader,Follower)模式的系统架构来保持集群中各副本间数据的一致性。

Zab协议的核心在于 消息广播崩溃恢复

消息广播:

Zk通过Leader来接收处理客户端的所有事务请求(Follower会将事务请求转发给Leader),zk收到一个事务请求时,处理流程如下:

  1. Leader将数据的变更以事务Proposal(并分配给该Proposal一个全局单调递增的Zxid,即事务唯一id)的形式广播到所有Follower服务器上
  2. Follower接收消息,并将Proposal消息以事务日志的形式保存于本机磁盘上,并发出Ack响应
  3. 一旦Leader收到过半Follwer的Ack确认消息,会再次向所有Follower服务器发送commit消息,要求Follower对前一个Proposal进行提交(过半写成功策略)

注意点

  • Zk事务提交过程类似于简化版的两阶段提交过程,只是不需要所有Follower响应,过半响应成功即可进行提交
  • 消息广播时,Leader与每个Follower建立FIFO的TCP长连接来进行网络通信,因此很好保证消息传输的顺序性
  • 考虑到分布式系统架构中网络因素的不可控,假设Leader向A,B 2个Follower发送commit消息时,A服务器由于网络原因没收到commit消息,但B收到了,此时A没对事务进行提交,B提交了事务,这时候就出现了数据不一致,即消息广播无法保证数据一致性

崩溃恢复:

在Leader服务器崩溃退出或者出现机器重启等情况,或者是集群中不存在过半机器与Leader正常通信时,那么在开始一轮新的原子广播之前,所有进程会首先使用崩溃恢复协议来达到一个一致的状态。

在介绍崩溃恢复之前先简单介绍下Zxid,Zxid是是一个全局递增的64位数字,高32位代表epoch编号,只有在Leader发生变化时才会+1,即每一个新Leader被选举产生,都会随之诞生一个新的epoch编号,同时将低32位置0。低32位代表counter计数器,即同一个Leader生命周期内的事务计数器,每发生一个事务,值+1。

崩溃恢复可分为2个核心步骤,Leader选举数据同步

Leader选举

Zookeeper中有2种Leader选举算法,一种基于basic paxos算法,一种基于fast paxos算法,默认选举算法为fast paxos算法。关于选举算法后续文章再做详细介绍,本文不做展开介绍。

数据同步

选出新的Leader后,Zookeeper就进入了数据同步过程,流程如下

  1. Leader等待Follower连接
  2. Follower连接Leader,将最大的Zxid发送给Leader
  3. Leader根据Follower的Zxid确定同步点,发送后续Proposal事务同步消息
  4. 完成同步后通知Follower 已经成为uptodate状态
  5. Follower收到uptodate消息后,又可以重新接受Client的请求进行服务了

Zookeeper学习笔记-基本概念及原理
本文对Zookeeper的简单介绍就到此为止,说的不对的还请多多指教。

工欲善其事必先利其器,环境都没有,怎么深入了解呢,所以呢,下篇文章小弟会介绍MacOs下Zookeeper环境的搭建以及ZkClient和Curator的使用,以便后续更好的对Zk应用场景做分析