<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>【无标题】</title>
<link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>
<body class="stackedit">
<div class="stackedit__html"><h1><a id="Zookeeper_0"></a>Zookeeper简介及核心概念</h1>
<nav>
<a href="#一Zookeeper简介">一、Zookeeper简介</a><br>
<a href="#二Zookeeper设计目标">二、Zookeeper设计目标</a><br>
<a href="#三核心概念">三、核心概念</a><br>
<a href="#31-集群角色">3.1 集群角色</a><br>
<a href="#32-会话">3.2 会话</a><br>
<a href="#33-数据节点">3.3 数据节点</a><br>
<a href="#34-节点信息">3.4 节点信息</a><br>
<a href="#35-Watcher">3.5 Watcher</a><br>
<a href="#36-ACL">3.6 ACL</a><br>
<a href="#四ZAB协议">四、ZAB协议</a><br>
<a href="#41-ZAB协议与数据一致性">4.1 ZAB协议与数据一致性</a><br>
<a href="#42--ZAB协议的内容">4.2 ZAB协议的内容</a><br>
<a href="#五Zookeeper的典型应用场景">五、Zookeeper的典型应用场景</a><br>
<a href="#51数据的发布订阅">5.1数据的发布/订阅</a><br>
<a href="#52-命名服务">5.2 命名服务</a><br>
<a href="#53-Master选举">5.3 Master选举</a><br>
<a href="#54-分布式锁">5.4 分布式锁</a><br>
<a href="#55-集群管理">5.5 集群管理</a><br>
</nav>
<h2><a id="Zookeeper_24"></a>一、Zookeeper简介</h2>
<p>Zookeeper 是一个开源的分布式协调服务,目前由 Apache 进行维护。Zookeeper 可以用于实现分布式系统中常见的发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。它具有以下特性:</p>
<ul>
<li><strong>顺序一致性</strong>:从一个客户端发起的事务请求,最终都会严格按照其发起顺序被应用到 Zookeeper 中;</li>
<li><strong>原子性</strong>:所有事务请求的处理结果在整个集群中所有机器上都是一致的;不存在部分机器应用了该事务,而另一部分没有应用的情况;</li>
<li><strong>单一视图</strong>:所有客户端看到的服务端数据模型都是一致的;</li>
<li><strong>可靠性</strong>:一旦服务端成功应用了一个事务,则其引起的改变会一直保留,直到被另外一个事务所更改;</li>
<li><strong>实时性</strong>:一旦一个事务被成功应用后,Zookeeper 可以保证客户端立即可以读取到这个事务变更后的最新状态的数据。</li>
</ul>
<h2><a id="Zookeeper_36"></a>二、Zookeeper设计目标</h2>
<p>Zookeeper 致力于为那些高吞吐的大型分布式系统提供一个高性能、高可用、且具有严格顺序访问控制能力的分布式协调服务。它具有以下四个目标:</p>
<h3><a id="21__40"></a>2.1 目标一:简单的数据模型</h3>
<p>Zookeeper 通过树形结构来存储数据,它由一系列被称为 ZNode 的数据节点组成,类似于常见的文件系统。不过和常见的文件系统不同,Zookeeper 将数据全量存储在内存中,以此来实现高吞吐,减少访问延迟。</p>
<p><img src="https://img-blog.csdnimg.cn/direct/d4b8f89ffa1a41bca94a743364c78fb9.png" alt="在这里插入图片描述"></p>
<h3><a id="22__47"></a>2.2 目标二:构建集群</h3>
<p>可以由一组 Zookeeper 服务构成 Zookeeper 集群,集群中每台机器都会单独在内存中维护自身的状态,并且每台机器之间都保持着通讯,只要集群中有半数机器能够正常工作,那么整个集群就可以正常提供服务。</p>
<p><img src="https://img-blog.csdnimg.cn/direct/c3bef9aaa0d9441887aa201b6a3b7018.png" alt=" "></p>
<h3><a id="23__54"></a>2.3 目标三:顺序访问</h3>
<p>对于来自客户端的每个更新请求,Zookeeper 都会分配一个全局唯一的递增 ID,这个 ID 反映了所有事务请求的先后顺序。</p>
<h3><a id="24__58"></a>2.4 目标四:高性能高可用</h3>
<p>ZooKeeper 将数据存全量储在内存中以保持高性能,并通过服务集群来实现高可用,由于 Zookeeper 的所有更新和删除都是基于事务的,所以其在读多写少的应用场景中有着很高的性能表现。</p>
<p><img src="https://img-blog.csdnimg.cn/direct/46b8ce5a94da4a16bf4bc56a8f75859d.png" alt="在这里插入图片描述"></p>
<h2><a id="_65"></a>三、核心概念</h2>
<h3><a id="31__67"></a>3.1 集群角色</h3>
<p>Zookeeper 集群中的机器分为以下三种角色:</p>
<ul>
<li><strong>Leader</strong> :为客户端提供读写服务,并维护集群状态,它是由集群选举所产生的;</li>
<li><strong>Follower</strong> :为客户端提供读写服务,并定期向 Leader 汇报自己的节点状态。同时也参与写操作“过半写成功”的策略和 Leader 的选举;</li>
<li><strong>Observer</strong> :为客户端提供读写服务,并定期向 Leader 汇报自己的节点状态,但不参与写操作“过半写成功”的策略和 Leader 的选举,因此 Observer 可以在不影响写性能的情况下提升集群的读性能。</li>
</ul>
<h3><a id="32__75"></a>3.2 会话</h3>
<p>Zookeeper 客户端通过 TCP 长连接连接到服务集群,会话 (Session) 从第一次连接开始就已经建立,之后通过心跳检测机制来保持有效的会话状态。通过这个连接,客户端可以发送请求并接收响应,同时也可以接收到 Watch 事件的通知。</p>
<p>关于会话中另外一个核心的概念是 sessionTimeOut(会话超时时间),当由于网络故障或者客户端主动断开等原因,导致连接断开,此时只要在会话超时时间之内重新建立连接,则之前创建的会话依然有效。</p>
<h3><a id="33__81"></a>3.3 数据节点</h3>
<p>Zookeeper 数据模型是由一系列基本数据单元 <code>Znode</code>(数据节点) 组成的节点树,其中根节点为 <code>/</code>。每个节点上都会保存自己的数据和节点信息。Zookeeper 中节点可以分为两大类:</p>
<ul>
<li><strong>持久节点</strong> :节点一旦创建,除非被主动删除,否则一直存在;</li>
<li><strong>临时节点</strong> :一旦创建该节点的客户端会话失效,则所有该客户端创建的临时节点都会被删除。</li>
</ul>
<p>临时节点和持久节点都可以添加一个特殊的属性:<code>SEQUENTIAL</code>,代表该节点是否具有递增属性。如果指定该属性,那么在这个节点创建时,Zookeeper 会自动在其节点名称后面追加一个由父节点维护的递增数字。</p>
<h3><a id="34__90"></a>3.4 节点信息</h3>
<p>每个 ZNode 节点在存储数据的同时,都会维护一个叫做 <code>Stat</code> 的数据结构,里面存储了关于该节点的全部状态信息。如下:</p>
<table>
<thead>
<tr>
<th><strong>状态属性</strong></th>
<th><strong>说明</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>czxid</td>
<td>数据节点创建时的事务 ID</td>
</tr>
<tr>
<td>ctime</td>
<td>数据节点创建时的时间</td>
</tr>
<tr>
<td>mzxid</td>
<td>数据节点最后一次更新时的事务 ID</td>
</tr>
<tr>
<td>mtime</td>
<td>数据节点最后一次更新时的时间</td>
</tr>
<tr>
<td>pzxid</td>
<td>数据节点的子节点最后一次被修改时的事务 ID</td