admin管理员组

文章数量:1565351

我参考了几十篇文章,总结了里面最重要的部分,并增加了许多自己的思考和理解,完成了这篇博客。我认为这篇博客很全,里面的内容也通俗易懂,想要了解Zookeeper的原理,本文应该就够了。另外,所有的参考文章链接已放到本文末尾,有需要的读者可自行查阅。

文章目录

    • 1. ZooKeeper 介绍
      • 1.1 什么是Zookeeper
      • 1.2 使用ZooKeeper的开源项目
      • 1.3 ZooKeeper的三种运行模式
    • 2. CAP和BASE理论
    • 3. Zookeeper的特点
    • 4. 一致性协议之 ZAB
      • 4.1 ZAB 中的三个角色
      • 4.2 ZXID和myid
      • 4.3 历史队列
      • 4.4 消息广播模式
      • 4.5 崩溃恢复模式
      • 4.6 脑裂问题
    • 5. Zookeeper选举机制
      • 5.1 初始化Leader选举
      • 5.2 运行时Leader选举
    • 6. Zookeeper数据模型
    • 7. Zookeeper监听通知机制
    • 8. Zookeeper会话(Session)
      • 8.1 会话状态
      • 8.2 会话ID的生成
      • 8.3 SessionTracker与ClientCnxn
      • 8.4 会话创建
      • 8.5 会话超时管理
      • 8.5 会话激活
      • 8.6 会话清理
      • 8.7 会话重连
    • 9. Zookeeper分布式锁
      • 9.1 获取锁
      • 9.2 释放锁
      • 9.3 Zk和Redis分布式锁的比较
    • 9. Zookeeper几个应用场景
      • 9.1 数据发布/订阅
      • 9.2 统一配置管理
      • 9.3 统一集群管理
      • 9.4 负载均衡
      • 9.5 命名服务

1. ZooKeeper 介绍

大家可以了解一下Paxos的小岛(Island),以便更好的理解Zookeeper的概念

1.1 什么是Zookeeper

ZooKeeper 是一个开源的分布式协调服务框架,为分布式系统提供一致性服务。

那么什么是分布式?什么是协调程序?和集群又有什么区别?

举一个例子来说明,现在有一个网上商城购物系统,并发量太大单机系统承受不住,那我们可以多加几台服务器支持大并发量的访问需求,这个就是所谓的Cluster 集群 。

如果我们将这个网上商城购物系统拆分成多个子系统,比如订单系统、积分系统、购物车系统等等,然后将这些子系统部署在不同的服务器上 ,这个时候就是 Distributed 分布式

对于集群来说,多加几台服务器就行(当然还得解决session共享,负载均衡等问题),而对于分布式来说,你首先需要将业务进行拆分,然后再加服务器,同时还要去解决分布式带来的一系列问题。比如各个分布式组件如何协调起来,如何减少各个系统之间的耦合度,如何处理分布式事务,如何去配置整个分布式系统,如何解决各分布式子系统的数据不一致问题等等。ZooKeeper 主要就是解决这些问题的。

1.2 使用ZooKeeper的开源项目

许多著名的开源项目用到了 ZooKeeper,比如:

  1. Kafka : ZooKeeper 主要为 Kafka 提供 Broker 和 Topic 的注册以及多个 Partition 的负载均衡等功能。
  2. Hbase : ZooKeeper 为 Hbase 提供确保整个集群只有一个 Master 以及保存和提供 regionserver 状态信息(是否在线)等功能。
  3. Hadoop : ZooKeeper 为 Namenode 提供高可用支持。
  4. Dubbo:阿里巴巴集团开源的分布式服务框架,它使用 ZooKeeper 来作为其命名服务,维护全局的服务地址列表。

1.3 ZooKeeper的三种运行模式

ZooKeeper 有三种运行模式:单机模式、伪集群模式和集群模式。

  • 单机模式:这种模式一般适用于开发测试环境,一方面我们没有那么多机器资源,另外就是平时的开发调试并不需要极好的稳定性。
  • 集群模式:一个 ZooKeeper 集群通常由一组机器组成,一般 3 台以上就可以组成一个可用的 ZooKeeper 集群了。组成 ZooKeeper 集群的每台机器都会在内存中维护当前的服务器状态,并且每台机器之间都会互相保持通信。
  • 伪集群模式:这是一种特殊的集群模式,即集群的所有服务器都部署在一台机器上。当你手头上有一台比较好的机器,如果作为单机模式进行部署,就会浪费资源,这种情况下,ZooKeeper 允许你在一台机器上通过启动不同的端口来启动多个 ZooKeeper 服务实例,从而以集群的特性来对外服务。

2. CAP和BASE理论

一个分布式系统必然会存在一个问题:因为分区容忍性(partition tolerance)的存在,就必定要求我们需要在系统可用性(availability)和数据一致性(consistency)中做出权衡 。这就是著名的 CAP 定理。

举个例子来说明,假如班级代表整个分布式系统,而学生是整个分布式系统中一个个独立的子系统。这个时候班里的小红小明偷偷谈恋爱被班里的小花发现了,小花欣喜若狂告诉了周围的人,然后小红小明谈恋爱的消息在班级里传播起来了。当在消息的传播(散布)过程中,你问班里一个同学的情况,如果他回答你不知道,那么说明整个班级系统出现了数据不一致的问题(因为小花已经知道这个消息了)。而如果他直接不回答你,因为现在消息还在班级里传播(为了保证一致性,需要所有人都知道才可提供服务),这个时候就出现了系统的可用性问题。

这个例子中前者就是 Eureka 的处理方式,它保证了AP(可用性),后者就 ZooKeeper 的处理方式,它保证了CP(数据一致性)。

CAP理论中,P(分区容忍性)是必然要满足的,因为毕竟是分布式,不能把所有的应用全放到一个服务器里面,这样服务器是吃不消的。所以,只能从AP(可用性)和CP(一致性)中找平衡。

怎么个平衡法呢?在这种环境下出现了BASE理论:即使无法做到强一致性,但分布式系统可以根据自己的业务特点,采用适当的方式来使系统达到最终的一致性。BASE理论由:Basically Avaliable 基本可用、Soft state 软状态、Eventually consistent 最终一致性组成。

  • 基本可用(Basically Available):基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。例如,电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层在该页面只提供降级服务。
  • 软状态(Soft State): 软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有多个副本,允许不同节点间副本同步的延时就是软状态的体现。
  • 最终一致性(Eventual Consistency): 最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。

一句话概括就是:平时系统要求是基本可用,运行有可容忍的延迟状态,但是,无论如何经过一段时间的延迟后系统最终必须达成数据是一致的。

ACID 是传统数据库常用的设计理念,追求强一致性模型。BASE 支持的是大型分布式系统,通过牺牲强一致性获得高可用性。

其实可能发现不管是CAP理论,还是BASE理论,他们都是理论,这些理论是需要算法来实现的,这些算法有2PC、3PC、Paxos、Raft、ZAB,它们所解决的问题全部都是:在分布式环境下,怎么让系统尽可能的高可用,而且数据能最终能达到一致

3. Zookeeper的特点

该部分来源于讲解 Zookeeper 的五个核心知识点。

  1. 集群:Zookeeper是一个领导者(Leader),多个跟随者(Follower)组成的集群。
  2. 高可用性:集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。
  3. 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
  4. 更新请求顺序进行:来自同一个Client的更新请求按其发送顺序依次执行。
  5. 数据更新原子性:一次数据更新要么成功,要么失败。
  6. 实时性:在一定时间范围内,Client能读到最新数据。
  7. 从设计模式角度来看,zk是一个基于观察者设计模式的框架,它负责管理跟存储大家都关心的数据,然后接受观察者的注册,数据反生变化zk会通知在zk上注册的观察者做出反应。
  8. Zookeeper是一个分布式协调系统,满足CP性,跟SpringCloud中的Eureka满足AP不一样。

4. 一致性协议之 ZAB

推荐大家先了解其他的一致性算法,如2PC、3PC、Paxos、Raft,可参考大数据中的 2PC、3PC、Paxos、Raft、ZAB。

作为一个优秀高效且可靠的分布式协调框架,ZooKeeper 在解决分布式数据一致性问题时并没有直接使用 Paxos ,而是专门定制了一致性协议叫做 ZAB(ZooKeeper Automic Broadcast) 原子广播协议,该协议能够很好地支持 崩溃恢复

4.1 ZAB 中的三个角色

ZAB 中三个主要的角色,Leader 领导者、Follower跟随者、Observer观察者 。

  • Leader :集群中 唯一的写请求处理者 ,能够发起投票(投票也是为了进行写请求)。
  • Follower:能够接收客户端的请求,如果是读请求则可以自己处理,如果是写请求则要转发给 Leader 。在选举过程中会参与投票,有选举权和被选举权
  • Observer :就是没有选举权和被选举权的 Follower

ZAB 协议中对 zkServer(即上面我们说的三个角色的总称) 还有两种模式的定义,分别是 消息广播崩溃恢复

4.2 ZXID和myid

ZooKeeper 采用全局递增的事务 id 来标识,所有 proposal(提议)在被提出的时候加上了ZooKeeper Transaction Id 。ZXID是64位的Long类型,这是保证事务的顺序一致性的关键。ZXID中高32位表示纪元epoch,低32位表示事务标识xid。你可以认为zxid越大说明存储数据越新,如下图所示:

  1. 每个leader都会具有不同的epoch值,表示一个纪元/朝代,用来标识 leader周期。每个新的选举开启时都会生成一个新的epoch,从1开始,每次选出新的Leader,epoch递增1,并会将该值更新到所有的zkServer的zxid的epoch。
  2. xid是一个依次递增的事务编号。数值越大说明数据越新,可以简单理解为递增的事务id。每次epoch变化,都将低32位的序号重置,这样保证了zxid的全局递增性。

每个ZooKeeper服务器,都需要在数据文件夹下创建一个名为myid的文件,该文件包含整个ZooKeeper集群唯一的id(整数)。例如,某ZooKeeper集群包含三台服务器,hostname分别为zoo1、zoo2和zoo3,其myid分别为1、2和3,则在配置文件中其id与hostname必须一一对应,如下所示。在该配置文件中,server.后面的数据即为myid

server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

4.3 历史队列

每一个follower节点都会有一个先进先出(FIFO)的队列用来存放收到的事务请求,保证执行事务的顺序。所以:

  • 可靠提交由ZAB的事务一致性协议保证
  • 全局有序由TCP协议保证
  • 因果有序由follower的历史队列(history queue)保证

4.4 消息广播模式

ZAB协议两种模式:消息广播模式和崩溃恢复模式。

说白了就是 ZAB 协议是如何处理写请求的,上面我们不是说只有 Leader 能处理写请求嘛?那么我们的 FollowerObserver 是不是也需要 同步更新数据 呢?总不能数据只在 Leader 中更新了,其他角色都没有得到更新吧。

第一步肯定需要 Leader 将写请求 广播 出去呀,让 Leader 问问 Followers 是否同意更新,如果超过半数以上的同意那么就进行 FollowerObserver 的更新(和 Paxos 一样)。消息广播机制是通过如下图流程保证事务的顺序一致性的:

  1. leader从客户端收到一个写请求
  2. leader生成一个新的事务并为这个事务生成一个唯一的ZXID
  3. leader将这个事务发送给所有的follows节点,将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower。
  4. follower节点将收到的事务请求加入到历史队列(history queue)中,当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK
  5. 当leader收到大多数follower(超过一半)的ack消息,leader会向follower发送commit请求(leader自身也要提交这个事务)
  6. 当follower收到commit请求时,会判断该事务的ZXID是不是比历史队列中的任何事务的ZXID都小,如果是则提交事务,如果不是则等待比它更小的事务的commit(保证顺序性)
  7. Leader将处理结果返回给客户端

过半写成功策略:Leader节点接收到写请求后,这个Leader会将写请求广播给各个Server,各个Server会将该写请求加入历史队列,并向Leader发送ACK信息,当Leader收到一半以上的ACK消息后,说明该写操作可以执行。Leader会向各个server发送commit消息,各个server收到消息后执行commit操作。

这里要注意以下几点:

  • Leader并不需要得到Observer的ACK,即Observer无投票权
  • Leader不需要得到所有Follower的ACK,只要收到过半的ACK即可,同时Leader本身对自己有一个ACK
  • Observer虽然无投票权,但仍须同步Leader的数据从而在处理读请求时可以返回尽可能新的数据

另外,Follower/Observer也可以接受写请求,此

本文标签: 史上最全万字详解原理