ZooKeeper分布式应用程序协调服务

一、定义

百度百科:Zookeeper(简称ZK)分布式服务框架主要是用来解决分布式应用中经常遇到的一些数据管理问题,提供分布式、高可用性的协调服务能力。

维基百科:ZooKeeper的架构通过冗余服务实现高可用性。因此,(客户端访问zk集群时)如果第一次无应答,客户端就可以询问(zk集群中的)另一台ZooKeeper主机。ZooKeeper节点将它们的数据存储于一个分层的命名空间,非常类似于一个文件系统。客户端可以在节点读写,从而以这种方式拥有一个共享的配置服务。更新是全序的。

不管是百度百科还是维基百科说的,我感觉都有点“玄乎”,第一次接触Zk的人,根本看不懂。咱就先把他当做一个能存储数据的服务吧(这种说法不严谨),然后咱们在一点点解释这个服务。

 

二、服务部署结构

zk是一个服务,这个服务本身是一个小集群,(这个集群可以自己配置,多安装几个zk,然后在配置文件内配置好兄弟服务的ip和端口)。其自身架构图如下所示:

a、客户端访问zk集群时,如果第一次无应答,客户端就可以询问(zk集群中的)另一台ZooKeeper主机。

b、一条消息被一个zkserver接收,它将被所有server接受。

c、更新只能成功或者失败,没有中间状态。只要成功,那么所有的zk服务器都会成功。

d、客户端的更新顺序与它们被发送的顺序相一致。

ZooKeeper 集群中的所有机器通过一个 Leader 选举过程来选定一台称为 “Leader” 的机器,Leader 既可以为客户端提供写服务又能提供读服务。

 

三、数据存储结构

Zookeeper将数据存储于内存中,具体而言,Znode是存储数据的最小单元。而Znode被以层次化的结构进行组织,形容一棵树。其对外提供的视图类似于Unix文件系统。树的根Znode节点相当于Unix文件系统的根路径。正如Unix中目录下可以有子目录一样,Znode结点下也可以挂载子结点,最终形成如下图。

节点类型

1、持久结点(PERSISTENT)
最常见的Znode类型,一旦创建将在一直存在于服务端,除非客户端通过删除操作进行删除。持久结点下可以创建子结点。
2、持久顺序结点(PERSISTENT_SEQUENTIAL)
在具有持久结点基本特性的基础上,会通过在结点路径后缀一串序号来区分多个子结点创建的先后顺序。这工作由Zookeeper服务端自动给我们做,只要在创建Znode时指定结点类型为该类型。
3、临时结点(EPHEMERAL)
临时结点的生命周期和客户端会话保持一致。客户端段会话存在的话临时结点也存在,客户端会话断开则临时结点会自动被服务端删除。临时结点下不能创建子结点。
4、临时顺序结点(EPHEMERAL_SEQUENTIAL)
具有临时结点的基本特性,又有顺序性。

注意临时顺序结点具有会话周期这个特性,临时节点下面不能创建子节点

 

四、ZooKeeper与CAP理论
先介绍一个概念,CAP理论,分布式领域中存在CAP理论:
a、C:Consistency,一致性,数据一致更新,所有数据变动都是同步的。
b、A:Availability,可用性,系统具有好的响应性能。
c、P:Partition tolerance,分区容错性。就是说必须分布式部署,只有分布式部署了,才具备分区容错性。

注:该理论已被证明:任何分布式系统只可同时满足两点,无法三者兼顾。 因此,将精力浪费在思考如何设计能满足三者的完美系统上是愚钝的,应该根据应用场景进行适当取舍。

这里只说一致性。一致性是指从系统外部读取系统内部的数据时,在一定约束条件下相同,即数据变动在系统内部各节点应该是同步的。根据一致性的强弱程度不同,可以将一致性级别分为如下几种:

a、强一致性(strong consistency)。任何时刻,任何用户都能读取到最近一次成功更新的数据。
b、单调一致性(monotonic consistency)。任何时刻,任何用户一旦读到某个数据在某次更新后的值,那么就不会再读到比这个值更旧的值。也就是说,可获取的数据顺序必是单调递增的。
c 、会话一致性(session consistency)。任何用户在某次会话中,一旦读到某个数据在某次更新后的值,那么在本次会话中就不会再读到比这个值更旧的值。会话一致性是在单调一致性的基础上进一步放松约束,只保证单个用户单个会话内的单调性,在不同用户或同一用户不同会话间则没有保障。
d、 最终一致性(eventual consistency)。用户只能读到某次更新后的值,但系统保证数据将最终达到完全一致的状态,只是所需时间不能保障。
e、 弱一致性(weak consistency)。用户无法在确定时间内读到最新更新的值。

我们知道ZooKeeper也是一种分布式系统,它在一致性上有人认为它提供的是一种强一致性的服务(通过sync操作),也有人认为是单调一致性(更新时的大多说概念),还有人为是最终一致性(顺序一致性),反正各有各的道理这里就不在争辩了。然后它在分区容错性和可用性上做了一定折中,这和CAP理论是吻合的。ZooKeeper从以下几点保证了数据的一致性
a 、顺序一致性
来自任意特定客户端的更新都会按其发送顺序被提交。也就是说,如果一个客户端将Znode z的值更新为a,在之后的操作中,它又将z的值更新为b,则没有客户端能够在看到z的值是b之后再看到值a(如果没有其他对z的更新)。
b 、原子性
每个更新要么成功,要么失败。这意味着如果一个更新失败,则不会有客户端会看到这个更新的结果。
c 、单一系统映像
一 个客户端无论连接到哪一台服务器,它看到的都是同样的系统视图。这意味着,如果一个客户端在同一个会话中连接到一台新的服务器,它所看到的系统状态不会比 在之前服务器上所看到的更老。当一台服务器出现故障,导致它的一个客户端需要尝试连接集合体中其他的服务器时,所有滞后于故障服务器的服务器都不会接受该 连接请求,除非这些服务器赶上故障服务器。
d、 持久性
一个更新一旦成功,其结果就会持久存在并且不会被撤销。这表明更新不会受到服务器故障的影响。

 

五、事件监听机制

Zookeeper中可以通过Watcher来实现事件监听机制。客户端可以向服务端注册Watcher用以监听某些事件,一旦该事件发生,服务端即会向客户端发送一个通知。其主要工作流程如下图所示。

Watcher是Zookeeper原生API中提供的事件监听接口,用户要实现事件监听必须实现该接口并重写process(WatchedEvent event)方法,该方法定义了客户端在接收到服务端事件通知后的回调逻辑。究竟服务端的什么事件可以被监听?

a.客户端与服务端成功建立会话。

b.监听的对应Znode被创建。

c.监听的对应Znode被创建。

d.Watcher监听的Znode的数据内容被改变,注意即使变更前后的数据内容完全一样也会触发该事件,或者理解成该事件的触发条件是Znode的版本号变更也没问题。

监听事件具备以下特性:

a.当监听器监听的事件被触发,服务端会发送通知给客户端,但通知信息中不包括事件的具体内容。以监听ZNode结点数据变化为例,当Znode的数据被改变,客户端会收到事件类型为NodeDataChanged的通知,但该Znode的数据改变成了什么客户端无法从通知中获取,需要客户端在收到通知后手动去获取。

b.Watcher是一次性的。一旦被��发将会失效。如果需要反复进行监听就需要反复进行注册。这么设计是为了减轻服务端的压力,但是对开发者而言却是相当不友好,不过不用着急,可以通过一些Zookeeper的开源客户端轻松实现对某一事件的永久监听。

 

六、故障处理

a.事务日志是指服务器在更新内存数据前先将事务操作以日志的方式写入磁盘,Leader和Follower服务器都会记录事务日志。

b.数据快照是指周期性通过深度遍历的方式将内存中的树形结构数据转入外存快照中。但要注意这种快照是"模糊"的,因为可能在做快照时内存数据发生了变化。但是因为Zookeeper本身对事务操作进行了幂等性保证,故在将快照加载进内存后会通过执行事务日志的方式来讲数据恢复到最新状态。

 

七、应用领域

zk的应用都是因为其独特的“特性”,我们在实际工作中,经常根据zk的特性使其在其他业务领域发挥不同的作用。

1、配置管理

替代配置文件,比如降链接字符串等信息保存到zk节点中,主要是根据zk的一致性协议:各个zk服务器自动同步数据节点的状态。

2、名字服务

类似dns,给ip地址起个名字(域名)。同样,在我们的服务特别多的时候,如果我们在本地保存服务的地址的时候将非常不方便,但是如果我们只需要访问一个大家都熟知的访问点,这里提供统一的入口,那么维护起来将方便得多了。

3、分布式事务锁

这个是最重要的,在分布式事务锁中,核心问题就是“获取锁”,”删除锁“。其中主要出现的问题就是“有锁的进程”造成“死锁”后,“发锁中心”如何处理这些“无用锁”。主要是利用了zk的“临时有序节点、会话、监听”。具体如何实现,我准备单独写分布式事务锁,请参考后续文章“redis分布式事务锁”和“zookeeper分布式事务锁”。

4、注册中心

微服务的 SOA 架构中,微服务应用和机器越来越多,调用方需要知道接口的网络地址,如果靠配置文件的方式去控制网络地址,对于动态新增机器,维护带来很大的问题。注册中心的一个重要的作用就是:“保存所有服务的名字,服务提供者的ip列表,服务消费者的IP列表”。zk的“一致性协议”加上“节点监听特性”,恰好可以提供服务发现功能,在微服务的 SOA 架构中,服务是一个集群提供的,当消费者访问某个服务时,就需要采用某种机制发现现在有哪些节点可以提供该服务(这也称之为服务发现,比如 Alibaba 开源的SOA 框架 Dubbo 就采用了 Zookeeper 作为服务发现的底层机制)。实现过程:

a、提供者provider:启动的时候向注册中心上报自己的网络信息
b、消费者consumer:启动的时候向注册中心上报自己的网络信息,拉取provider的相关网络信息

分析:使用zk的好处是,各个服务在写入注册中心的时候,都会和zk注册中心建立会话机制,如果“服务C”宕机,那么,其在“注册中心”写下的ip和端口也会自动删除。此时消费者监听到zk数据节点有变动,重新读取到的“服务地址列表的数据”也会随之发生改变。

 

添加评论

Loading