Zookeeper
zookeepepr
是一个经典的分布式数据一致性解决方案。作为分布式系统的分布式协同服务,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调存储服务。
一、概述
1.1 使用场景
zookeepepr
是一个经典的分布式数据一致性解决方案。作为分布式系统的分布式协同服务,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调存储服务。
- 维护配置信息
- 分布式锁服务
- 集群管理
- 生成分布式唯一ID
1.1.1 维护配置信息
java
编程经常会遇到配置项,比如数据库的url
、 schema
、user
和 password
等。通常这些配置项我们会放置在配置文件中,再将配置文件放置在服务器上当需要更改配置项时,需要去服务器上修改对应的配置文件。
但是随着分布式系统的兴起,由于许多服务都需要使用到该配置文件,因此有必须保证该配置服务的高可用性(highavailability
)和各台服务器上配置数据的一致性。
通常会将配置文件部署在一个集群上,然而一个集群动辄上千台服务器,此时如果再一台台服务器逐个修改配置文件那将是非常繁琐且危险的的操作,因此就需要一种服务,能够高效快速且可靠地完成配置项的更改等操作,并能够保证各配置项在每台服务器上的数据一致性。
Zookeeper
就可以提供这样一种服务,其使用Zab
这种一致性协议来保证一致性。现在有很多开源项目使用Zookeeper
来维护配置,如在 hbase
中,客户端就是连接一个 Zookeeper
,获得必要的 hbase
集群的配置信息,然后才可以进一步操作。还有在开源的消息队列 kafka
中,也便用Zookeeper
来维护 brokers
的信息。在 alibaba
开源的soa
框架dubbo
中也广泛的使用Zookeeper
管理一些配置来实现服务治理。
1.1.2 分布式锁服务
一个集群是一个分布式系统,由多台服务器组成。为了提高并发度和可靠性,多台服务器上运行着同一种服务。当多个服务在运行时就需要协调各服务的进度,有时候需要保证当某个服务在进行某个操作时,其他的服务都不能进行该操作,即对该操作进行加锁,如果当前机器挂掉后,释放锁并 fail over
到其他的机器继续执行该服务
1.1.3 集群管理
一个集群有时会因为各种软硬件故障或者网络故障,出现某些服务器挂掉而被移除集群,或将某些服务器加入到集群中的情况,Zookeeper
会将这些服务器加入/移出的情况通知给集群中其他正常工作的服务器,以及时调整存储和计算等任务的分配和执行。此外Zookeeper
还会对故障服务器做出诊断并尝试修复。
1.1.4 生产分布式唯一ID
在过去的单库单表型系统中,通常可以使用数据库字段自带的auto_ increment
属性来自动为每条记录生成一个唯一的ID
。但是分库分表后,就无法在依靠数据库的auto_increment
属性来唯一标识一条记录了。此时我们就可以用Zookeeper
在分布式环境下生成全局唯一ID
。
做法如下:每次要生成一个新id
时,创建一个持久顺序结点,创建操作返回的结点序号,即为新id
,然后把比自己结点小的删除即可
1.2 设计目标
zooKeeper
致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。
-
高性能
Zookeeper
将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,尤其用于以读为主的应用场景 -
高可用
Zookeeper
一般以集群的方式对外提供服务,一般3~5
台机器就可以组成一个可用的Zookeeper
集群了,每台机器都会在内存中维护当前的服务器状态,井且每台机器之间都相互保持着通信。只要集群中超过一半的机器都能够正常工作,那么整个集群就能够正常对外服务 -
严格顺序访问
对于来自客户端的每个更新请求,
Zookeeper
都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序
1.3 架构及特点
1.3.1 分布式相关理论
(1)CAP理论
事物总是发展的,人类社会信息总量在不断增大,对于RDBM系统管理的数据容量已经从GB级别演进到TB级别,又从TB级别演进到PB级别,数据量不断增大,原有的RDBM已经力不从心。
为解决数据容量持续增加带来的挑战,第一提升系统的计算能力,可以并行对应数据进行分区域或者分块计算,然后对应计算结果进行汇集处理,第二提升数据的读取速度,单存储结点的读取速度必定存在限制,需要指出多存储结点的DB系统,分布式数据库DDBS系统诞生了,分布式数据库系统可以支持多个存储结点。但是分布式数据库采用对存储结点构造后,带来了一个新的问题,这个问题就是CAP理论的魔咒。
CAP 理论指出对于一个分布式计算系统来说,不可能同时满足以下三点:
- 一致性:在分布式环境中,一致性是指数据在多个副本之间是否能够保持一致的特性,等同于所有结点访问同一份最新的数据副本。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。
- 可用性:每次请求都能获取到正确的响应,但是不保证获取的数据为最新数据,因为此时势必不允许加入锁机制,因此也就无法保证数据的一致性。
- 分区容错性:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须要实现的,所以只能在一致性和可用性之间进行权衡在这三个基本需求中,最多只能同时满足其中的两项,P 是必须的,因此只能在 CP 和 AP 中选择,Zookeeper 保证的是 CP,对比 spring cloud 系统中的注册中心 eruka 实现的是 AP。
(2)BASE理论
为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
强一致性:即即时一致性,读取到的数据总是最新的
弱一致性:允许读到的数据不是最新的
BASE 是 Basically Available(基本可用)、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。
- 基本可用:在分布式系统出现故障,允许损失部分可用性(服务降级、页面降级)。
- 软状态:允许分布式系统出现中间状态。而且中间状态不影响系统的可用性。这里的中间状态是指不同的 data replication(数据备份结点)之间的数据更新可以出现延时的最终一致性。
- 最终一致性:指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。
1.3.2 架构及特点
(1)架构
- 领导者(Leader):负责进行投票的发起和决议,更新系统状态
- 学习者(learner):包括跟随者(Follower)和观察者(observer)
- Follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
- observer可以接受客户端连接,将写请求转发给Leader,但observer不参加投票过程,只同步Leader的状态,observer的目的是为了扩展系统,提高读取速度
- 客户端(client):请求发起方
(2)特点
-
最终一致性:Zookeeper 允许系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。
-
顺序性:来自客户端的更新将按照其发送顺序进行执行。
-
原子性:更新成功或失败。没有中间状态的结果。
-
统一视图:无论客户端连接到哪个服务器,客户端都将看到相同服务的数据视图。
-
可靠性: 一旦数据更新被执行了,它将从那时起持续到客户端覆盖更新。
-
及时性:确保系统的客户视图在特定时间范围内是最新的。
1.4 数据模型
Zookeeper 结点中存储的服务器相关信息,并不存储代码等处理逻辑,是一个管理服务器、协调分布式应用的服务架构。
1.4.1 数据结构
在 Zookeeper 中,数据信息被保存在一个个数据结点上,这些结点被称为 Znode 。Znode 是 Zookeeper 中最小的数据单位,在 Znode 下又可以继续挂载 Znode
Zookeeper
结点在结构上表现为树状。树中的各个结点被称为znode
,一个znode
可以有多个子结点。znode
,兼具文件和目录两种特点,即像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。每一个结点都可以存储数据,只是需要注意的是存储的容量是有限,一般不能超过 1MB。
一个znode
大体上分为3
个部分:
- 结点的数据:即
znode data
(结点path
,结点data
)的关系就像是Java map
中的key value
关系 - 结点的子结点
children
- 结点的属性
stat
:用来描述当前结点的创建、修改记录,包括cZxid
、ctime
等
结点属性 | 说明 |
---|---|
cZxid | 数据结点创建时的事务ID——针对于Zookeeper数据结点的管理:我们对结点数据的一些写操作都会导致Zookeeper自动地为我们去开启一个事务,并且自动地去为每一个事务维护一个事务ID |
ctime | 数据结点创建时的时间 |
mZxid | 数据结点最后一次更新时的事务ID |
mtime | 数据结点最后一次更新时的时间 |
pZxid | 该数据结点的子结点最后一次被修改时的事务ID |
cversion | 子结点的更改次数 |
dataVersion | 结点数据的更改次数 |
aclVersion | 结点的ACL更改次数——类似linux的权限列表,维护的是当前结点的权限列表被修改的次数 |
ephemeralOwner | 如果结点是临时结点,则表示创建该结点的会话的SessionID;如果是持久结点,该属性值为0 |
dataLength | 数据内容的长度 |
numChildren | 数据结点当前的子结点个数 |
1.4.2 结点类型
Znode的类型在创建时确定并且之后不能再修改。
- 持久结点(
persistent node
),不依赖于客户端会话,客户端与服务端断开连接后,创建的结点不会被删除。只有当客户端明确要删除该持久 Znode 时才会被删除 - 临时结点(
ephemeral node
),客户端断开连接后,Zookeeper 会自动删除临时结点,且该类结点不允许有子结点【由于临时 Znode 会因为创建者会话过期被删除,所以不允许临时结点拥有子结点】
1.4.3 结点形式
顺序结点(
sequential node
),每次创建顺序结点时,Zookeeper 都会在路径后面自动添加上10位的数字,从1开始,最大是2147483647 (2^32-1)【每个顺序结点都有一个单独的计数器,并且单调递增的,由Zookeeper的Leader
实例维护。】
Znode实际上有四种形式,默认是persistent
。
- PERSISTENT 持久结点: 如
create /test/a "hello"
,通过create <path> <data>
参数指定为持久结点 - PERSISTENT_SEQUENTIAL 持久顺序结点 ,通过
create -s <path> <data>
参数指定为顺序结点 - EPHEMERAL 临时结点,通过
create -e <path> <data>
参数指定为顺序结点 - EPHEMERAL_SEQUENTIAL 临时顺序结点 ,通过
create -s -e <path> <data>
参数指定为临时及顺序结点