zoukankan      html  css  js  c++  java
  • Zookeeper到底是干嘛的

    在Zookeeper的官网上有这么一句话:ZooKeeper is a centralized(统一的) service for maintaining(维护) configuration information, naming, providing distributed synchronization, and providing group services.

    这主要描述Zookeeper可以干哪些事情:配置管理名字服务提供分布式同步以及集群管理

    那这些服务又到底是什么呢?

    我们为什么需要这样的服务?

    我们又为什么要使用Zookeeper来实现呢,使用Zookeeper有什么优势?

    接下来会挨个介绍这些到底是什么,以及有哪些开源系统中使用了。

    一、配置管理

      在开发应用中除了代码外,还有一些就是各种配置。比如数据库连接等。一般我们都是使用配置文件的方式,在代码中引入这些配置文件。当我们只有一种配置,只有一台服务器,并且不经常修改的时候,使用配置文件是一个很好的做法,但是如果我们配置非常多,有很多服务器都需要这个配置,而且还可能是动态的话使用配置文件就不是个好主意了。这个时候往往需要寻找一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣的应用程序都可以获得变更。比如我们可以把配置放在数据库里,然后所有需要配置的服务都去这个数据库读取配置。但是,因为很多服务的正常运行都非常依赖这个配置,所以需要这个集中提供配置服务的服务具备很高的可靠性。一般我们可以用一个集群来提供这个配置服务,但是用集群提升可靠性,那如何保证配置在集群中的一致性呢? 这个时候就需要使用一种实现了一致性协议的服务了。Zookeeper就是这种服务,它使用ZAB协议这种一致性协议来提供一致性。现在有很多开源项目使用Zookeeper来维护配置,比如在HBase中,客户端就是连接一个Zookeeper,获得必要的HBase集群的配置信息,然后才可以进一步操作。还有在开源的消息队列Kafka中,也使用Zookeeper来维护broker(代理)的信息。在Alibaba开源的SOA框架Dubbo中也广泛的使用Zookeeper管理一些配置来实现服务治理。

    dubbo是分布式的远程调用框架,推荐使用zk作为注册和中心,利用zk来实现负载均衡,存储服务的元数据,向外提供服务

    二、名字服务

      名字服务这个比较好理解。比如为了通过网络访问一个系统,我们得知道对方服务器的【ip:port】或域名,IP地址对人类记忆非常不友好,这个时候就需要使用方便记忆的域名来访问目标系统。但计算机实际上是不能识别域名的。该怎么办?如果互联网中每台计算机里都备有一份域名到IP地址的映射关系(host文件),这个倒是能解决一部分问题,但是如果域名对应的IP发生变化了又该怎么办呢?于是就有了DNS(Domain name resolution)这个东西。在通过网络访问一个目标系统时,只需要访问一个大家熟知的(DNS)的服务器站点,它就会告诉你这个域名对应的IP是什么。同样的在应用中也会存在这类问题,特别是在应用服务特别多的时候,如果在本地保存服务的地址的时候会非常不方便,但是如果只需要访问一个大家都熟知的站点,并提供统一的入口,那么维护起来会方便很多。

    三、分布式锁

      其实在第一篇文章中已经介绍了Zookeeper是一个分布式协调服务。我们可以利用Zookeeper来协调多个分布式进程之间的活动。比如在一个分布式环境中,为了提高可靠性,集群的每台服务器上都部署了同样的服务。但是一件事情如果集群中的每个服务器都进行的话,那相互之间就要协调,编程起来将非常复杂。而如果我们只让一个服务进行操作,那又存在单点。通常还有一种做法就是使用分布式锁,在某个时刻只让一个服务去干活,当这台服务出问题的时候锁释放,立即fail over(故障转移)让另外的服务去干活。这在很多分布式系统中都是这么做,这种设计有一个更好听的名字叫Leader Election(leader选举)。比如HBase的Master就是采用这种机制。但要注意的是分布式锁跟同一个进程的锁还是有区别的,所以使用的时候要比同一个进程里的锁更谨慎的使用。

    科普:分布式与集群的区别

      其实分布式不一定就是不同的组件,同一个组件也可以,关键在于是否通过交换信息的方式进行协作。比如说Zookeeper的节点都是对等的,但它自己就构成一个分布式系统。

      也就是说,分布式是指通过网络连接的多个组件,通过交换信息协作而形成的系统。而集群,是指同一种组件的多个实例,形成的逻辑上的整体。

      这两个概念并不完全冲突,分布式系统也可以是一个集群,例子就是前面说的zookeeper等,它的特征是服务之间会互相通信协作,这是属于是分布式系统,并且不是集群的情况,就是多个不同组件构成的系统;

      是集群,并且不是分布式系统的情况:比如多个经过负载均衡的HTTP服务器,它们之间不会互相通信,如果不带上负载均衡的部分的话,一般不叫做分布式系统。

    假如A是服务那么N个A就是集群。将X服务拆分成A、B、C三种不同的服务,此时ABC三种服务构成一种分布式服务,分布式就将一个服务拆成多个服务,集群是多台相同服务一起提供服务

    四、集群管理

      在分布式系统的集群中,经常会由于各种原因,比如硬件故障,软件故障,网络问题,有些集群节点会进进出出。会有新的节点加入进来,也会有老的节点退出集群。这个时候,集群中其他机器就需要感知到这种变化,然后根据这种变化做出相应决策。比如在一个分布式存储系统中,有一个中央控制节点负责存储任务的分配,当有新的存储工作进入系统的时候,这个中央控制节点就要根据集群的最新状态来分配存储节点。这个时候中央控制节点就需要具备动态感知集群目前的状态的能力。不仅如此,比如一个分布式的SOA(微服务)架构中,某个服务是一个集群提供的,当消费者访问这个服务的时候,就需要采用某种机制发现现在有哪些节点可以提供该服务(这就称为服务发现,比如Alibaba开源的SOA框架Dubbo就采用了Zookeeper作为服务发现的底层机制)。还有开源的Kafka队列就采用了Zookeeper作为Cosnumer的上下线管理。

    自己的一些理解:

      Leader可以接受client请求,也接收其他Server转发的写请求,负责更新系统状态。 Follower也可以接收client请求,如果是写请求将转发给Leader来更新系统状态,读请求则由Follower的内存数据库直接响应。

    img

    事物操作

      在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper都会为其分配一个全局唯一的事务ID,用 ZXID 表示,通常是一个64位的数字。每一个 ZXID对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的全局顺序。

    Watcher(事件监听器)

      是ZooKeeper中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去。这个机制是ZooKeeper实现分布式协调服务的重要特性。

      ZooKeeper支持一种Watch(监听)操作,Client可以在某个ZNode上设置一个Watcher,来Watch该ZNode上的变化。如果该ZNode上有相应的变化,就会触发这个Watcher,把相应的事件通知给设置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即触发一次就会被取消,如果想继续Watch的话,需要客户端重新设置Watcher。

      ZooKeeper数据模型的结构,整体上可以看作是一棵树,每个节点称做一个ZNode。每个ZNode都可以通过其路径被唯一标识,并且每个ZNode上可存储少量数据(默认是1M, 可以通过配置修改, 通常不建议在ZNode上存储大量的数据)

    节点状态

      每个集群中的节点都有一个状态(LOOKING,LEADING, FOLLOWING, OBSERVING这4种中的一种),每个节点启动的时都是LOOKING状态,如果这个节点参与选举但最后不是leader,则状态是FOLLOWING,如果不参与选举则是OBSERVING,leader的状态是LEADING。

    关于ZooKeeper集群服务器数

      ZooKeeper官方确实给出了关于奇数的建议。

      一个 ZooKeeper 集群如果要对外提供可用的服务,那么集群中必须要有过半的机器正常工作并且彼此之间能够正常通信。基于这个特性,如果想搭建一个能够允许N台机器down掉的集群,那么就要部署一个由 2*N+1 台服务器构成的 ZooKeeper 集群。因此,一个由 3 台机器构成的ZooKeeper 集群,能够在挂掉 1 台机器后依然正常工作,而对于一个由 5 台服务器构成的ZooKeeper 集群,能够对2台机器挂掉的情况进行容灾。注意,如果是一个由6台服务器构成的 ZooKeeper 集群,同样只能够挂掉 2 台机器,因为如果挂掉 3 台,剩下的机器就无法实现过半了。

      【集群中只要有超过半数的机器是正常的,那么整个集群对外就可用】

      也就是说如果有2个zookeeper,那么只要有1个死了zookeeper就不能用了,因为1没有过半,所以2个zookeeper的死亡容忍度为0;同理,要是有3个zookeeper,一个死了,还剩下2个正常的,过半了,所以3个zookeeper的容忍度为1;同理你多列举几个:2->0;3->1;4->1;5->2;6->2会发现一个规律,2n和2n-1的容忍度是一样的,都是n-1,所以为了更加高效,何必增加那一个不必要的zookeeper呢,这就是为什么服务器集群的数量建议为奇数的原因。

    ZooKeeper可伸缩性

      ZooKeeper为什么要引入Observer这个角色呢?在ZooKeeper中引入Observer,主要是为了使ZooKeeper具有更好的可伸缩性。伸缩性在这里是说,如果系统的工作负载可以通过给系统分配更多的节点资源来降低整个系统的负载(想象一下集群),那么就称这个系统是可伸缩的;一个不可伸缩的系统是无法通过增加节点资源来提升系统对外服务的性能,甚至会在工作负载增加时,性能会急剧下降。

      Observer出现以前,ZooKeeper的伸缩性由Follower来实现,我们可以通过添加Follower节点的数量来保证ZooKeeper服务的读性能。但随着Follower节点数量的增加(参与投票节点数量的增加),ZooKeeper服务的写性能受到了影响(写操作需要经过投票机制)。

    ZAB协议规定

      Client的所有写请求,都要转发给ZK服务中唯一的ServerLeader,由Leader根据该请求发起一个Proposal(提案/请求)。然后,其他的Server对这个Proposal进行Vote(投票)。之后,Leader对Vote(投票)进行收集,当Vote数量过半时Leader会向所有的Server通知这个写操提案通过的消息。最后,当Client所连接的Server收到该消息时,会把该操作更新到自己的内存中,并对Client的写请求做出回应。

    img

      从图中可以看出, ZooKeeper服务器在上述协议中实际扮演了两个职能。它们一方面从客户端接受连接与操作请求,另一方面对操作结果进行投票。这两个职能在 ZooKeeper集群扩展的时候彼此制约。

      例如,当希望增加ZK服务中Client数量(并发度)的时候,那么就需要增加Server的数量,来支持这么多的客户端。但在观察ZAB协议对写请求的处理过程可以发现,增加服务器的数量,则增加了Leader在协议中投票过程的压力,因为Leader节点必须等待集群中过半Server响应投票机制,于是节点的增加使得部分计算机运行较慢,从而拖慢整个投票过程的可能性也随之提高,写操作也会随之下降。这正是在实际操作中看到的问题——随着 ZooKeeper 集群变大,写操作的吞吐量会下降。

    所以,不得不在增加Client数量的愿望与希望保持较好吞吐性能的愿望之间进行权衡取舍。为了打破这个耦合的关系,就引入了不参与投票的服务器称为Observer。 Observer可以接受客户端的连接,并将写请求转发给Leader节点。但是Leader节点不会要求 Observer参加投票。相反,Observer不参与投票过程,仅仅在上述第3歩那样,和其他服务节点一起得到投票结果,更新到自己的内存中,并对client的写请求做出反应。

    zookeeper的角色

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

    2、学习者(learner): 包括跟随者(follower)和观察者(observer)。

    ​ 跟随者(follower)用于接受客户端请求并向客户端返回结果,在选举过程中参与投票。

    ​ 观察者(observer)可以接受客户端连接,将写请求转发给leader,但是它不参与投票过程,只同步leader的状态,它的目的是为了扩展系统,提高读写的速度。

    3、客户端(client):请求发起方。

    Zookeeper工作流程-Leader

    1 .恢复数据;

    2 .维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;

    3 .Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。

    PING 消息是指Learner的心跳信息;

    REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;

    ACK消息是 Follower的对提议的回复,超过半数的Follower通过,则commit该提议;

    REVALIDATE(重新验证)消息是用来延长SESSION有效时间。

    img

    Zookeeper工作流程-Follower

    Follower主要有四个功能:

    1.向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);

    2.接收Leader消息并进行处理;

    3.接收Client的请求,如果为写请求,发送给Leader进行投票;

    4.更新自己的状态,并返回Client结果。

    Follower的消息循环处理如下几种来自Leader的消息

    1 .PING消息: 心跳消息;

    2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;

    3 .COMMIT消息:服务器端最新一次提案的信息;

    4 .UPTODATE消息:表明同步完成;

    5 .REVALIDATE消息:根据Leader返回的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;

    6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制从Leader得到最新的更新。

    Zookeeper节点数据操作流程

    img

    注:

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

    2.Follwer把请求转发给Leader处理

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

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

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

    6.Follwer根据Leader的通知决定是否更新自己的内存,并且把写请求的结果返回给Client;

    Zookeeper设计目的

    1.最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。

    2.可靠性:具有简单、健壮、良好的性能,如果消息被某一台服务器接受,那么它将被所有的服务器接受。

    3.实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

    4.等待无关(wait-free):慢的或者失效的client不干预快速的client的请求,使得每个client都能进行有效的等待。

    5.原子性:更新只能成功或者失败,没有中间状态。

    6.顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

    原文

    https://www.cnblogs.com/ultranms/p/9585191.html

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利
  • 相关阅读:
    「考试」省选27
    「考试」省选26
    「考试」省选25
    $dy$讲课总结
    「笔记」$Min\_25$筛
    「考试」省选24
    「总结」多项式生成函数例题(4)
    「总结」多项式生成函数相关(4)
    「考试」省选23
    「总结」后缀3
  • 原文地址:https://www.cnblogs.com/hhddd-1024/p/15345053.html
Copyright © 2011-2022 走看看