Zookeeper的原理和架构设计,以及应用场景

什么是 Zookeeper

Zookeeper 分布式服务框架是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:

  1.  统一命名服务
  2.  状态同步服务
  3.  集群管理
  4.  分布式应用配置项的管理等

Zookeeper已经成为Hadoop生态系统中的基础组件。

一、分布式协调技术

在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术。那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种临界资源,防止造成"脏数据"的后果。这时,有人可能会说这个简单,写一个调度算法就轻松解决了。说这句话的人,可能对分布式系统不是很了解,所以才会出现这种误解。如果这些进程全部是跑在一台机上的话,相对来说确实就好办了,问题就在于他是在一个分布式的环境下,这时问题又来了,那什么是分布式呢?这个一两句话我也说不清楚,但我给大家画了一张图希望能帮助大家理解这方面的内容,如果觉得不对尽可拍砖,来咱们看一下这张图,如图1.1所示。

图 1.1 分布式系统图

给大家分析一下这张图,在这图中有三台机器,每台机器各跑一个应用程序。然后我们将这三台机器通过网络将其连接起来,构成一个系统来为用户提供服务,对用户来说这个系统的架构是透明的,他感觉不到我这个系统是一个什么样的架构。那么我们就可以把这种系统称作一个分布式系统

那我们接下来再分析一下,在这个分布式系统中如何对进程进行调度,我假设在第一台机器上挂载了一个资源,然后这三个物理分布的进程都要竞争这个资源,但我们又不希望他们同时进行访问,这时候我们就需要一个协调器,来让他们有序的来访问这个资源。这个协调器就是我们经常提到的那个,比如说"进程-1"在使用该资源的时候,会先去获得锁,"进程1"获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,"进程1"用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。这个分布式锁也就是我们分布式协调技术实现的核心内容,那么如何实现这个分布式呢,那就是我们后面要讲的内容。

二、分布式锁的实现

好我们知道,为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。那么这个锁怎么实现呢?这实现起来确实相对来说比较困难的。

1.1 面临的问题

在看了图1.1所示的分布式环境之后,有人可能会感觉这不是很难。无非是将原来在同一台机器上对进程调度的原语,通过网络实现在分布式环境中。是的,表面上是可以这么说。但是问题就在网络这,在分布式系统中,所有在同一台机器上的假设都不存在:因为网络是不可靠的。

比如,在同一台机器上,你对一个服务的调用如果成功,那就是成功,如果调用失败,比如抛出异常那就是调用失败。但是在分布式环境中,由于网络的不可靠,你对一个服务的调用失败了并不表示一定是失败的,可能是执行成功了,但是响应返回的时候失败了。还有,A和B都去调用C服务,在时间上 A还先调用一些,B后调用,那么最后的结果是不是一定A的请求就先于B到达呢? 这些在同一台机器上的种种假设,我们都要重新思考,我们还要思考这些问题给我们的设计和编码带来了哪些影响。还有,在分布式环境中为了提升可靠性,我们往往会部署多套服务,但是如何在多套服务中达到一致性,这在同一台机器上多个进程之间的同步相对来说比较容易办到,但在分布式环境中确实一个大难题。

所以分布式协调远比在同一台机器上对多个进程的调度要难得多,而且如果为每一个分布式应用都开发一个独立的协调程序。一方面,协调程序的反复编写浪费,且难以形成通用、伸缩性好的协调器。另一方面,协调程序开销比较大,会影响系统原有的性能。所以,急需一种高可靠、高可用的通用协调机制来用以协调分布式应用。

1.2 分布式锁的实现者

目前,在分布式协调技术方面做得比较好的就是Google的Chubby还有Apache的ZooKeeper他们都是分布式锁的实现者。有人会问既然有了Chubby为什么还要弄一个ZooKeeper,难道Chubby做得不够好吗?不是这样的,主要是Chbby是非开源的,Google自家用。后来雅虎模仿Chubby开发出了ZooKeeper,也实现了类似的分布式锁的功能,并且将ZooKeeper作为一种开源的程序捐献给了Apache,那么这样就可以使用ZooKeeper所提供锁服务。而且在分布式领域久经考验,它的可靠性,可用性都是经过理论和实践的验证的。所以我们在构建一些分布式系统的时候,就可以以这类系统为起点来构建我们的系统,这将节省不少成本,而且bug也 将更少。

三、ZooKeeper概述

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列分布式通知/协调等。

注意:ZooKeeper性能上的特点决定了它能够用在大型的、分布式的系统当中。从可靠性方面来说,它并不会因为一个节点的错误而崩溃。除此之外,它严格的序列访问控制意味着复杂的控制原语可以应用在客户端上。ZooKeeper在一致性、可用性、容错性的保证,也是ZooKeeper的成功之处,它获得的一切成功都与它采用的协议——Zab协议是密不可分的,这些内容将会在后面介绍。

前面提到了那么多的服务,比如分布式锁、配置维护、组服务等,那它们是如何实现的呢,我相信这才是大家关心的东西。ZooKeeper在实现这些服务时,首先它设计一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。那么我就从这三个方面,给大家介绍一下ZooKeeper。

四、ZooKeeper数据模型

4.1 ZooKeeper数据模型Znode

ZooKeeper拥有一个层次的命名空间,这个和标准的文件系统非常相似,如下图3.1 所示。

图4.1 ZooKeeper数据模型与文件系统目录树

 

从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,ZooKeeper树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:

(1) 引用方式

Zonde通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如关键配额信息。

(2) Znode结构

ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:

 stat:此为状态信息, 描述该Znode的版本, 权限等信息

 data:与该Znode关联的数据

 children:该Znode下的子节点

ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但常规使用中应该远小于此值。

(3) 数据访问

ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

(4) 节点类型

ZooKeeper中的节点有两种,分别为临时节点永久节点。节点的类型在创建时即被确定,并且不能改变。

① 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点。

② 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

(5) 顺序节点

当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。

(6) 观察

客户端可以在节点上设置watch,我们称之为监视器。当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量。

4.2 ZooKeeper中的时间

ZooKeeper有多种记录时间的形式,其中包含以下几个主要属性:

(1) Zxid

致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。也就是说,也就是说,每个对节点的改变都将产生一个唯一的Zxid。如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。实际上,ZooKeeper的每个节点维护者三个Zxid值,为别为:cZxid、mZxid、pZxid。

 cZxid: 是节点的创建时间所对应的Zxid格式时间戳。
② mZxid:是节点的修改时间所对应的Zxid格式时间戳。

实现中Zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个 新的epoch。低32位是个递增计数。 (2) 版本号

对节点的每一个操作都将致使这个节点的版本号增加。每个节点维护着三个版本号,他们分别为:

① version:节点数据版本号
② cversion:子节点版本号
③ aversion:节点所拥有的ACL版本号

4.3 ZooKeeper节点属性

通过前面的介绍,我们可以了解到,一个节点自身拥有表示其状态的许多重要属性,如下图所示。

图 4.2 Znode节点属性结构

五、ZooKeeper服务中操作

在ZooKeeper中有9个基本操作,如下图所示:

图 5.1 ZooKeeper类方法描述

更新ZooKeeper操作是有限制的。delete或setData必须明确要更新的Znode的版本号,我们可以调用exists找到。如果版本号不匹配,更新将会失败。

更新ZooKeeper操作是非阻塞式的。因此客户端如果失去了一个更新(由于另一个进程在同时更新这个Znode),他可以在不阻塞其他进程执行的情况下,选择重新尝试或进行其他操作。

尽管ZooKeeper可以被看做是一个文件系统,但是处于便利,摒弃了一些文件系统地操作原语。因为文件非常的小并且使整体读写的,所以不需要打开、关闭或是寻地的操作。

六、Watch触发器

(1) watch概述

ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()、getChildren()及getData()。watch事件是一次性的触发器,当watch的对象状态发生改变时,将会触发此对象上watch所对应的事件。watch事件将被异步地发送给客户端,并且ZooKeeper为watch机制提供了有序的一致性保证。理论上,客户端接收watch事件的时间要快于其看到watch对象状态变化的时间。

(2) watch类型

ZooKeeper所管理的watch可以分为两类:

 数据watch(data  watches):getDataexists负责设置数据watch
② 孩子watch(child watches):getChildren负责设置孩子watch

我们可以通过操作返回的数据来设置不同的watch:

① getData和exists:返回关于节点的数据信息
② getChildren:返回孩子列表

因此

① 一个成功的setData操作将触发Znode的数据watch

 一个成功的create操作将触发Znode的数据watch以及孩子watch

③ 一个成功的delete操作将触发Znode的数据watch以及孩子watch

(3) watch注册与处触发

图 6.1 watch设置操作及相应的触发器如图下图所示:

① exists操作上的watch,在被监视的Znode创建删除数据更新时被触发。
 getData操作上的watch,在被监视的Znode删除数据更新时被触发。在被创建时不能被触发,因为只有Znode一定存在,getData操作才会成功。
 getChildren操作上的watch,在被监视的Znode的子节点创建删除,或是这个Znode自身被删除时被触发。可以通过查看watch事件类型来区分是Znode,还是他的子节点被删除:NodeDelete表示Znode被删除,NodeDeletedChanged表示子节点被删除。

Watch由客户端所连接的ZooKeeper服务器在本地维护,因此watch可以非常容易地设置、管理和分派。当客户端连接到一个新的服务器时,任何的会话事件都将可能触发watch。另外,当从服务器断开连接的时候,watch将不会被接收。但是,当一个客户端重新建立连接的时候,任何先前注册过的watch都会被重新注册。

(4) 需要注意的几点

Zookeeper的watch实际上要处理两类事件:

① 连接状态事件(type=None, path=null)

这类事件不需要注册,也不需要我们连续触发,我们只要处理就行了。

② 节点事件

节点的建立,删除,数据的修改。它是one time trigger,我们需要不停的注册触发,还可能发生事件丢失的情况。

上面2类事件都在Watch中处理,也就是重载的process(Event event)

节点事件的触发,通过函数exists,getData或getChildren来处理这类函数,有双重作用:

① 注册触发事件

② 函数本身的功能

函数的本身的功能又可以用异步的回调函数来实现,重载processResult()过程中处理函数本身的的功能。

七、ZooKeeper应用举例 

为了方便大家理解ZooKeeper,在此就给大家举个例子,看看ZooKeeper是如何实现的他的服务的,我以ZooKeeper提供的基本服务分布式锁为例。

7.1 分布式锁应用场景

在分布式锁服务中,有一种最典型应用场景,就是通过对集群进行Master选举,来解决分布式系统中的单点故障。什么是分布式系统中的单点故障:通常分布式系统采用主从模式,就是一个主控机连接多个处理节点。主节点负责分发任务,从节点负责处理任务,当我们的主节点发生故障时,那么整个系统就都瘫痪了,那么我们把这种故障叫作单点故障。如下图7.1和7.2所示:

图 7.1 主从模式分布式系统               图7.2 单点故障

     

7.2 传统解决方案

传统方式是采用一个备用节点,这个备用节点定期给当前主节点发送ping包,主节点收到ping包以后向备用节点发送回复Ack,当备用节点收到回复的时候就会认为当前主节点还活着,让他继续提供服务。如图7.3所示:

图 7.3 传统解决方案

当主节点挂了,这时候备用节点收不到回复了,然后他就认为主节点挂了接替他成为主节点如下图7.4所示:

图 7.4传统解决方案

但是这种方式就是有一个隐患,就是网络问题,来看一网络问题会造成什么后果,如下图7.5所示:

图 7.5 网络故障

也就是说我们的主节点的并没有挂,只是在回复的时候网络发生故障,这样我们的备用节点同样收不到回复,就会认为主节点挂了,然后备用节点将他的Master实例启动起来,这样我们的分布式系统当中就有了两个主节点也就是---双Master,出现Master以后我们的从节点就会将它所做的事一部分汇报给了主节点,一部分汇报给了从节点,这样服务就全乱了。为了防止出现这种情况,我们引入了ZooKeeper,它虽然不能避免网络故障,但它能够保证每时每刻只有一个Master。我么来看一下ZooKeeper是如何实现的。

7.3 ZooKeeper解决方案

(1) Master启动

在引入了Zookeeper以后我们启动了两个主节点,"主节点-A"和"主节点-B"他们启动以后,都向ZooKeeper去注册一个节点。我们假设"主节点-A"锁注册地节点是"master-00001","主节点-B"注册的节点是"master-00002",注册完以后进行选举,编号最小的节点将在选举中获胜获得锁成为主节点,也就是我们的"主节点-A"将会获得锁成为主节点,然后"主节点-B"将被阻塞成为一个备用节点。那么,通过这种方式就完成了对两个Master进程的调度。

图7.6 ZooKeeper Master选举

(2) Master故障

如果"主节点-A"挂了,这时候他所注册的节点将被自动删除,ZooKeeper会自动感知节点的变化,然后再次发出选举,这时候"主节点-B"将在选举中获胜,替代"主节点-A"成为主节点。

图7.7 ZooKeeper Master选举

(3) Master 恢复

图7.8 ZooKeeper Master选举

如果主节点恢复了,他会再次向ZooKeeper注册一个节点,这时候他注册的节点将会是"master-00003",ZooKeeper会感知节点的变化再次发动选举,这时候"主节点-B"在选举中会再次获胜继续担任"主节点","主节点-A"会担任备用节点。

Zookeeper的基本原理和架构

1、Zookeeper的角色

» 领导者(leader):负责进行投票的发起和决议,更新系统状态。

» 学习者(learner):包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票。

» Observer:可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度

» 客户端(client):请求发起方

Zookeeper的原理和架构设计,以及应用场景-mikechen的互联网架构

Zookeeper的原理和架构设计,以及应用场景-mikechen的互联网架构

 

• Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。

Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

• 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

• 每个Server在工作过程中有三种状态:

LOOKING:当前Server不知道leader是谁,正在搜寻

LEADING:当前Server即为选举出来的leader

FOLLOWING:leader已经选举出来,当前Server与之同步

其他文档:http://www.cnblogs.com/lpshou/archive/2013/06/14/3136738.html

2、Zookeeper 的读写机制

» Zookeeper是一个由多个server组成的集群

» 一个leader,多个follower

» 每个server保存一份数据副本

» 全局数据一致

» 分布式读写

» 更新请求转发,由leader实施

3、Zookeeper 的保证

» 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行

» 数据更新原子性,一次数据更新要么成功,要么失败

» 全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的

» 实时性,在一定事件范围内,client能读到最新数据

4、Zookeeper节点数据操作流程

Zookeeper的原理和架构设计,以及应用场景-mikechen的互联网架构

1.在Client向Follwer发出一个写的请求

2.Follwer把请求发送给Leader

3.Leader接收到以后开始发起投票并通知Follwer进行投票

4.Follwer把投票结果发送给Leader

5.Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;

6.Follwer把请求结果返回给Client

5、Zookeeper工作原理

» Zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。

Zab协议有两种模式,它们分别是:恢复模式和广播模式。

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server的完成了和leader的状态同步以后,恢复模式就结束了。

6、数据一致性与paxos 算法

• 据说Paxos算法的难理解与算法的知名度一样令人敬仰,所以我们先看如何保持数据的一致性,这里有个原则就是:

• 在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。

• Paxos算法解决的什么问题呢,解决的就是保证每个节点执行相同的操作序列。好吧,这还不简单,master维护一个全局写队列,所有写操作都必须 放入这个队列编号,那么无论我们写多少个节点,只要写操作是按编号来的,就能保证一致性。没错,就是这样,可是如果master挂了呢。

• Paxos算法通过投票来对写操作进行全局编号,同一时刻,只有一个写操作被批准,同时并发的写操作要去争取选票,

只有获得过半数选票的写操作才会被 批准(所以永远只会有一个写操作得到批准),其他的写操作竞争失败只好再发起一

轮投票,就这样,在日复一日年复一年的投票中,所有写操作都被严格编号排 序。编号严格递增,当一个节点接受了一个

编号为100的写操作,之后又接受到编号为99的写操作(因为网络延迟等很多不可预见原因),它马上能意识到自己 数据

不一致了,自动停止对外服务并重启同步过程。任何一个节点挂掉都不会影响整个集群的数据一致性(总2n+1台,除非挂掉大于n台)。

总结

• Zookeeper 作为 Hadoop 项目中的一个子项目,是 Hadoop 集群管理的一个必不可少的模块,它主要用来控制集群中的数据,

如它管理 Hadoop 集群中的 NameNode,还有 Hbase 中 Master Election、Server 之间状态同步等。

关于Paxos算法可以查看文章 Zookeeper全解析——Paxos作为灵魂

推荐书籍:《从Paxos到Zookeeper分布式一致性原理与实践》

7、Observer

• Zookeeper需保证高可用和强一致性;

• 为了支持更多的客户端,需要增加更多Server;

• Server增多,投票阶段延迟增大,影响性能;

• 权衡伸缩性和高吞吐率,引入Observer

• Observer不参与投票;

• Observers接受客户端的连接,并将写请求转发给leader节点;

• 加入更多Observer节点,提高伸缩性,同时不影响吞吐率

8、 为什么zookeeper集群的数目,一般为奇数个?

•Leader选举算法采用了Paxos协议;

•Paxos核心思想:当多数Server写成功,则任务数据写成功如果有3个Server,则两个写成功即可;如果有4或5个Server,则三个写成功即可。

•Server数目一般为奇数(3、5、7)如果有3个Server,则最多允许1个Server挂掉;如果有4个Server,则同样最多允许1个Server挂掉由此,

我们看出3台服务器和4台服务器的的容灾能力是一样的,所以为了节省服务器资源,一般我们采用奇数个数,作为服务器部署个数。

9、Zookeeper 的数据模型

» 层次化的目录结构,命名符合常规文件系统规范

» 每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识

» 节点Znode可以包含数据和子节点,但是EPHEMERAL类型的节点不能有子节点

» Znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本

» 客户端应用可以在节点上设置监视器

» 节点不支持部分读写,而是一次性完整读写

10、Zookeeper 的节点

» Znode有两种类型,短暂的(ephemeral)和持久的(persistent)

» Znode的类型在创建时确定并且之后不能再修改

» 短暂znode的客户端会话结束时,zookeeper会将该短暂znode删除,短暂znode不可以有子节点

» 持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除

» Znode有四种形式的目录节点

» PERSISTENT(持久的)

» EPHEMERAL(暂时的)

» PERSISTENT_SEQUENTIAL(持久化顺序编号目录节点)

» EPHEMERAL_SEQUENTIAL(暂时化顺序编号目录节点)

Zookeeper的应用场景

1. 配置管理

这个好理解,分布式系统都有好多机器,比如我在搭建hadoop的HDFS的时候,需要在一个主机器上(Master节点)配置好HDFS需要的各种配置文件,然后通过scp命令把这些配置文件拷贝到其他节点上,这样各个机器拿到的配置信息是一致的,才能成功运行起来HDFS服务。

Zookeeper提供了这样的一种服务:一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣的都可以获得变更。这样就省去手动拷贝配置了,还保证了可靠和一致性。

Zookeeper的原理和架构设计,以及应用场景-mikechen的互联网架构

2. 名字服务

这个可以简单理解为一个电话薄,电话号码不好记,但是人名好记,要打谁的电话,直接查人名就好了。

分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务;

  •  类似于域名与ip之间对应关系,域名容易记住;
  •  通过名称来获取资源或服务的地址,提供者等信息

3. 分布式锁

碰到分布二字貌似就难理解了,其实很简单。单机程序的各个进程需要对互斥资源进行访问时需要加锁,那分布式程序分布在各个主机上的进程对互斥资源进行访问时也需要加锁。很多分布式系统有多个可服务的窗口,但是在某个时刻只让一个服务去干活,当这台服务出问题的时候锁释放,立即fail over到另外的服务。这在很多分布式系统中都是这么做,这种设计有一个更好听的名字叫Leader Election(leader选举)。举个通俗点的例子,比如银行取钱,有多个窗口,但是呢对你来说,只能有一个窗口对你服务,如果正在对你服务的窗口的柜员突然有急事走了,那咋办?找大堂经理(zookeeper)!大堂经理指定另外的一个窗口继续为你服务!

4. 集群管理

在分布式的集群中,经常会由于各种原因,比如硬件故障,软件故障,网络问题,有些节点会进进出出。有新的节点加入进来,也有老的节点退出集群。这个时候,集群中有些机器(比如Master节点)需要感知到这种变化,然后根据这种变化做出对应的决策。我已经知道HDFS中namenode是通过datanode的心跳机制来实现上述感知的,那么我们可以先假设Zookeeper其实也是实现了类似心跳机制的功能吧!

zookeeper配置说明

基于3.4.13版本
基础配置
配置项 示例 说明
tickTime tickTime=2000 心跳,单位ms
dataDir dataDir=/opt/zookeeper/data 数据存放目录
clientPort clientPort=2181 客户端链接端口
clientPortAddress clientPortAddress=172.0.0.1 多网卡时可以为每个ip配置不同的端口,默认情况下都是clientPort。(3.3.0版本以上)
高级配置
配置项 示例 说明
dataLogDir dataLogDir=/opt/zookeeper/logdata 事物日志存储路径,不设置则写入到dataDir目录下
globalOutstandingLimit globalOutstandingLimit=500 最大链接数据,默认1000,请求数据较大可以适当降低该值
preAllocSize preAllocSize=32M
每个事务日志的大小,每多少个事务生成一次快照,snapCount参数配合

使用,和默认64M。

snapCount snapCount=50000
每个事务快照的事务数据,默认100000,为了防止集群同时进行快照生成,

每隔服务的事务数为[snapCount/2+1,snapCount]之间的随机数。

maxClientCnxns maxClientCnxns=64 单个客户端最大链接数据,防止Dos等恶意链接,默认60,设置0为不做限制。
minSessionTimeout minSessionTimeout=4000
客户端请求超时时间区间,单位ms。

当客户端设置的超时时间小于minSessionTimeout时,

置minSessionTimeout为超时时间,默认2*tickTime。(3.3.0版本以上)

maxSessionTimeout maxSessionTimeout=40000
客户端请求超时时间区间,单位ms。

当客户端设置的超时时间小于maxSessionTimeout时,

置maxSessionTimeout为超时时间,默认20*tickTime。(3.3.0版本以上)

autopurge.snapRetainCount autopurge.snapRetainCount=5
留存快照数量,开启时,服务只保留最近几次快照,

清理其他历史快照,默认3,最小3。(3.4.0版本以上)

autopurge.purgeInterval autopurge.purgeInterval=1
清楚历史快照的时间,单位小时。大于0时开启,

默认为0不开启。(3.4.0版本以上)

syncEnabled syncEnabled=false
是否开启同步,开启后服务存储快照,

减少观察者重启恢复的时间,默认true.

集群配置
配置项 示例 说明
electionAlg electionAlg=3
选举leader方式,0、1、2基于UDP选举,3基于TCP快速选取,

默认3。

initLimit initLimit=10 leader与follower之间链接初始化心跳次数,10*2s后置为失败
syncLimit syncLimit=5 leader与follower之间同步重试次数,5*2s后置为失败
leaderServes leaderServes=no
leader服务是否接受客户端连接,默认yes。

可以牺牲读取吞吐量为代价增加更高的更新吞吐量,可以设置no。

节点大于3个时建议关闭。

peerType peerType=observer
服务在集群集群中的角色,默认participant参与者,

可以设置为observer观察者。

server.x=serverIp1:port1:port2:peerType server.1=serverIp1:2888:3888
server.2=serverIp2:2788:3788
server.3=serverIp3:2688:3688
server.4=serverIp4:2588:3588:observer
集群服务器,通过查找数据目录中的myid文件内容来获取编号,

myid文件中ASCII和配种中的x一致,
hostname表示本地服务ip
port1端口号,用于正常连接工作
port2端口号,用于leader的选举操作,当electionAlg配置为0时不需要配置。
伪集群每个端口号需不一样。
节点最后加上observer 设置该点为观察者模式,节点较少时不建议设置。

group.x=server1:server2… group.1=1:4:7
group.2=2:5:8
group.3=3:6:9
选取leader时的投票分组,每个group为一票,

当组内服务器大多数投票时,group投票成功。

weight.x=num weight.1=1
weight.2=1
weight.3=1
weight.4=1
weight.5=1
weight.6=1
weight.7=1
weight.8=1
weight.9=1 组内票数的权重,可以一票当多票。集合group使用
cnxTimeout cnxTimeout=3
leader选举时通知链接的超时时间,单位s,默认5s。

适用于electionAlg=3的tcp链接的情况。

4lw.commands.whitelist 4lw.commands.whitelist=stat,ruok,conf,isro
四字符命令系统白名单,开启指定命令,逗号分隔。

*代表所有四字符系统命令。
默认情况开启除了“wchp”和“wchc”之外的所有。

(3.4.10版本以上)

ipReachableTimeout ipReachableTimeout=0
ip地址可达超时时间,单位ms.当server配置使用域名时,

且域名对于多个ip,
默认情况直接使用该域名的第一个ip,不做是否可达检查。
如设置该值,将依次检查域名对于的ip是否可达,

并使用最先可达的ip.
如果都不可达,将无奈的使用第一个ip地址,此时该服务不可用。
是否可达校验使用Java API的InAddiaby.IsAccess(long TimeOutlook)方法。

tcpKeepAlive tcpKeepAlive=false server之间的tcp链接是否为长连接,默认false.
JAVA环境变量配置
权限配置
zookeeper.DigestAuthenticationProvider.superDigest

默认disabled,通过修改启动文件zkServer.sh文件中的java环境变了开启。

开启方法:

以参数"super:<password>"来调用org.apache.zookeeper.server.auth.DigestAuthenticationProvider可以生成一个超级用户.

用过命令“java -cp "/usr/lib/zookeeper/zookeeper.jar:/usr/lib/zookeeper/lib/slf4j-api-1.7.25.jar"

org.apache.zookeeper.server.auth.DigestAuthenticationProvider super:pwd123”生成加密密码<data>.

然后用前面命令生成的"super:<data>"作为服务启动的Java系统属性传递给进程, 就开启了这个功能.

函数同步时间
fsync.warningthresholdms=500

单位ms,当同步时间超出这个值时,会输出一条警告消息,默认1000。(3.3.4版本以上)

启动文件zkserver.sh中java环境变量设置。

伪集群配置
tickTime=2000
dataDir=/opt/zookeeper/zookeeper1/data
dataLogDir=/opt/zookeeper/zookeeper1/logdata
clientPort=2181
initLimit=10
syncLimit=5
server.1=127.0.0.1:2881:3881
server.2=127.0.0.1:2882:3882

 

posted @ 2022-02-07 13:41  hanease  阅读(612)  评论(0编辑  收藏  举报