1、zk的产生、优劣、基础知识

1、分布式系统理解、优点、面临的挑战:
1)分布式系统是由独立的计算机通过网络连接在一起,并且通过一些组件来相互交流和协作来完成一个共同的目标。
2)分布式应用的优点:
可靠性:单个或几个系统的故障不会使整个系统出现故障;
可扩展性:可以在需要时增加性能,通过添加更多机器,在应用程序配置中进行微小的更改,而不会有停机时间;
透明性:隐藏系统的复杂性,并将其显示为单个实体/应用程序;
3)分布式应用的挑战
竞争条件:两个或多个机器尝试执行特定任务,实际上只需在任意给定时间由单个机器完成。例如,共享资源只能在任意给定时间由单个机器修改。
死锁:两个或多个操作等待彼此无限期完成。
不一致:数据的部分失败。

2、分布式系统的两种通信方式:
分布式系统的协调工作就是通过某种方式,让每个节点的信息能够同步和共享。这依赖于服务进程之间的通信。通信方式有两种:
1)通过网络进行信息共享:
这就像现实世界,开发leader在会上把任务传达下去,组员通过听leader命令或者看leader的邮件知道自己要干什么。当任务分配有变化时,leader会单独告诉组员,或者再次召开会议。信息通过人与人之间的直接沟通,完成传递。
2)通过共享存储:
这就好比开发leader按照约定的时间和路径,把任务分配表放到了svn上,组员每天去svn上拉取最新的任务分配表,然后干活。其中svn就是共享存储。更好一点的做法是,当svn文件版本更新时,触发邮件通知,每个组员再去拉取最新的任务分配表。这样做更好,因为每次更新,组员都能第一时间得到消息,从而让自己手中的任务分配表永远是最新的。此种方式依赖于中央存储。ZooKeeper对分布式系统的协调,使用的是共享存储方式,其实共享存储,分布式应用也需要和存储进行网络通信。网络通信是分布式系统并发设计的基础。
另一种解释:通过ZooKeeper实现分布式协同的原理,和项目组通过SVN同步工作任务的例子是一样的。ZooKeeper就像是svn,存储了任务的分配、完成情况等共享信息。每个分布式应用的节点就是组员,订阅这些共享信息。当主节点(组leader),对某个从节点的分工信息作出改变时,相关订阅的从节点得到zookeeper的通知,取得自己最新的任务分配。完成工作后,把完成情况存储到zookeeper。主节点订阅了该任务的完成情况信息,所以将得到zookeeper的完工的通知。以ZooKeeper来代替svn和邮件系统。

3、判断分布式系统好坏的指标:
资源共享:例如存储空间,计算能力,数据,和服务等等
扩展性:从软件和硬件上增加系统的规模
并发性:多个用户同时访问
性能: 确保当负载增加的时候,系统想要时间不会有影响
容错性:尽管一些组件暂时不可用了,整个系统仍然是可用的
API抽象:系统的独立组件对用户隐藏,仅仅暴露服务
注:通过ZooKeeper 开发者可以很轻松的实现对分布式系统的配置管理、命名服务、分布式锁、集群关系操作,检测节点的加入和离开。

4、zookeeper的产生、应用、使用zk的好处:
    zookeeper实际上是yahoo开发的,用于分布式中一致性处理的框架。最初其作为研发Hadoop时的副产品,在⼤数据领域得到⼴泛应用。ZooKeeper以Fast Paxos算法为基础,同时为了解决活锁问题,对Fast Paxos算法进⾏了优化,因此也可以⼴泛用于⼤数据之外的其他分布式系统,为⼤型分布式系统提供可靠的协作处理功能。比如小米公司的米聊,其后台就采用了ZooKeeper作为分布式服务的统⼀协作系统。⽽阿里公司的开发⼈员也⼴泛使用ZooKeeper,并对其进⾏了适当修改,开源了⼀款TaoKeeper软件,以适应自身业务需要。当前分布式系统中大量应用了zookeeper,以至于zookeeper成为了各种分布式系统的基础组件,其地位之重要,可想而知。著名的hadoop、kafka、dubbo 都是基于zookeeper而构建。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协 调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
  Apache ZooKeeper是由集群(节点组)使用的一种服务,用于在自身之间协调,并通过稳健的同步技术维护共享数据。ZooKeeper本身是一个分布式应用程序,为写入分布式应用程序提供服务。
4.1 ZooKeeper提供的常见服务(或者说是使用场景)如下 :
1)命名服务:按名称标识集群中的节点。它类似于DNS,但仅对于节点。
2)配置管理:加入节点的最近的和最新的系统配置信息。
3)集群管理:实时地在集群和节点状态中加入/离开节点。
4)选举算法:选举一个节点作为协调目的的leader。
5)锁定和同步服务:在修改数据的同时锁定数据。此机制可帮助你在连接其他分布式应用程序(如Apache HBase)时进行自动故障恢复。
6)高度可靠的数据注册表:即使在一个或几个节点关闭时也可以获得数据。
分布式应用程序提供了很多好处,但它们也抛出了一些复杂和难以解决的挑战。ZooKeeper框架提供了一个完整的机制来克服所有的挑战。竞争条件和死锁使用故障安全同步方法进行处理。另一个主要缺点是数据的不一致性,ZooKeeper使用原子性解析。
   7)生产全局id:一种是通过持久顺序节点、一种通过节点的版本号,具体代码示例请移步。
  a.持久顺序节点的特性:(PERSISTENT_SEQUENTIAL)
    在ZooKeeper中,每个父节点都会为他的第一级子节点维护一份顺序,用于记录下每个子节点创建的先后顺序。基于这个顺序特性,在创建子节点的时候,可以设置这个标记,那么在创建节点过程中,ZooKeeper会自动为给定节点加上一个数字后缀,作为一个新的、完整的节点名。另外需要注意的是,这个数字后缀的上限是整型的最大值。
  b.通过使用版本号来保证分布式数据原子性操作
  ZooKeeper中为数据节点引入了版本的概念,每个数据节点都具有三种类型的版本信息,对数据节点的任何更新操作都会引起版本号的变化。
4.2 使用ZooKeeper的好处:
1)简单的分布式协调过程
2)同步:服务器进程之间的相互排斥和协作。此过程有助于Apache HBase进行配置管理。
3)有序的消息
4)序列化:根据特定规则对数据进行编码。确保应用程序运行一致。这种方法可以在MapReduce中用来协调队列以执行运行的线程。
5)可靠性
6)原子性:数据转移完全成功或完全失败,但没有事务是部分的。

5、ZK基础:
5.1 zk中的数据节点:zookeeper的结构其实就是一个树形结构,leader就相当于其中的根结点,其它节点就相当于 follow节点,每个节点都保留自己的数据在内存中
   很多用于协作的原语常常在很多应⽤之间共享,因此,设计⼀个⽤于协作需求的服务的⽅法往往是提供原语列表,暴露出每个原语的实例化调⽤⽅法,并直接控制这些实例。这种设计存在⼀些重⼤的缺陷:⾸先,我们要么预先提出⼀份详尽的原语列表,要么提供API的扩展,以便引⼊新的原语;其次,以这种⽅式实现原语的服务使得应⽤丧失了灵活性。因此,在ZooKeeper中我们另辟蹊径。ZooKeeper并不直接暴露原语,取⽽代之,它暴露了由⼀⼩部分调⽤⽅法组成的类似⽂件系统的API,以便允许应⽤实现⾃⼰的原语。我们通常使⽤菜谱(recipes)来表⽰这些原语的实现。菜谱包括ZooKeeper操作和维护⼀个⼩型的数据节点,这些节点被称znode,采⽤类似于⽂件系统的层级树状结构进⾏管理。

    

 


   ·/workers节点作为⽗节点,其下每个znode⼦节点保存了系统中⼀个可用从节点信息。如图2-1所示,有⼀个从节点(foot.com:2181)。
  ·/tasks节点作为⽗节点,其下每个znode⼦节点保存了所有已经创建并等待从节点执⾏的任务的信息,主-从模式的应用的客户端在/tasks下添加⼀个znode⼦节点,用来表示⼀个新任务,并等待任务状态的znode节点。
  ·/assign节点作为⽗节点,其下每个znode⼦节点保存了分配到某个从节点的⼀个任务信息,当主节点为某个从节点分配了⼀个任务,就会在/assign下增加⼀个⼦节点。

  需要注意的是,ZooKeeper并不允许局部写⼊或读取znode节点的数据。当设置⼀个znode节点的数据或读取时,znode节点的内容会被整个替换或全部读取进来。

  5.2 zookeeper的节点分两类:持久节点(persistent)、临时节点(ephemeral)、顺序(sequential)
  a.持久节点:只能通过delete删除,即显式删除才消失。持久节点是指一旦这个树形结构被创建,除非主动进行对树节点的移除操作,否则这个节点将一直保存在 ZooKeeper 上。可以通过持久类型的znode为应⽤保存⼀些数据,即使znode的创建者不再属于应⽤系统时,数据也可以保存下来⽽不丢失。

  持久节点的使用:在主-从模式例⼦中,需要保存从节点的任务分配情况,即使分配任务的主节点已经崩溃了。
  b.临时节点:会话终止即自动消失;临时节点的生命周期跟客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。除此之外,当某个客户端(不⼀定是创建者)主动删除该节点时,该节点临时节点也会消失。因此,只有临时节点不允许有子节点。如果临时节点被删除,则下一个合适的节点将填充其位置。临时节点在leader选举中起着重要作用。

  临时节点的使用:在主从模式的例⼦中,当主节点创建的znode为临时节点时,该节点的存在意味着现在有⼀个主节点,且主节点状态处于正常运⾏中。如果主znode消失后,该znode节点仍然存在,那么系统将⽆法监测到主节点崩溃。这样就可以阻⽌系统继续进⾏,因此这个znode需要和主节点⼀起消失。我们也在从节点中使⽤临时的znode,如果⼀个从节点失效,那么会话将会过期,之后znode/workers也将⾃动消失。
  c.顺序节点:顺序节点可以是持久的或临时的。当一个新的znode被创建为一个顺序节点时,ZooKeeper通过将10位的序列号附加到原始名称来设置znode的路径。例如,如果将具有路径 /myapp 的znode创建为顺序节点,则ZooKeeper会将路径更改为 /myapp0000000001 ,并将下一个序列号设置为0000000002。如果两个顺序节点是同时创建的,那么ZooKeeper不会对每个znode使用相同的数字。顺序节点在锁定和同步中起重要作用。

5.1 集群角色:ZK集群有Leader(领导)、Follower(追随者)、Observer(观察员)三种角色,一个ZooKeeper集群同一时刻只会有一个 Leader,其他都是 Follower 或 Observer。
1)ZooKeeper 集群的所有机器通过一个 Leader 选举过程来选定一台被称为Leader的机器,Leader服务器为客户端提供读和写服务。
2)Follower 和 Observer都能提供读服务,不能提供写服务。
3)Follower 和 Observer区别在于Observer不参与Leader选举过程,也不参与写操作的"过半写成功"策略,因此Observer可以在不影响写性能的情况下提升集群的读性能。
5.3 Sessions(会话)
会话对于ZooKeeper的操作非常重要。会话中的请求按FIFO顺序执行。一旦客户端连接到服务器,将建立会话并向客户端分配会话ID,客户端以特定的时间间隔发送心跳以保持会话有效。如果ZooKeeper集合在超过服务器开启时指定的期间(会话超时)都没有从客户端接收到心跳,则它会判定客户端死机。会话超时通常以毫秒为单位。当会话由于任何原因结束时,在该会话期间创建的临时节点也会被删除。当客户端通过某一个特定的语言套件来创建一个zookeeper句柄时,他就会通过服务建立一个会话。客户端初始连接到集合中的某一个服务器或者一个独立服务器。客户端通过TCP协议与服务器进行连接,并通信。但是当会话无法与当前服务器继续通信时,会话可能转移到另一个服务器上。zk客户端透明的转移一个会话到不同的服务器上。
创建一个会话需要设置会话超时这一参数,该参数设置了zk服务器允许会话被声明为超时之前存在的时间。如果经过时间t之后服务器接收不到这个会话的任何消息,服务就会声明会话过期。而客户端侧,如果经过t/3时间,未收到任何消息,客户端将向服务器发送心跳消息。再经过2t/3的时间后,zk客户端开始寻找其他的服务器,而此时它还有t/3的时间寻找。
思考题:仲裁模式下客户端会尝试连接到哪个服务器?
  仲裁模式下应用需要传递可用的服务器列表给客户端,告知客户端可以连接的服务器信息,并选择一个进行连接。
备注:判断服务器是否可用的重要标识是:事务标识符(zkid)。如果尝试连接的服务器有一个较低的zkid,那么会继续尝试连接其他的服务器。
5.4 watch(监视)
监视是一种简单的机制,使客户端收到关于ZooKeeper集合中的更改的通知。客户端可以在读取特定znode时设置Watches。Watches会向注册的客户端发送任何znode(客户端注册表)更改的通知。Znode更改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。
5.5 事件、监视点、通知:
1)事件(event):表⽰⼀个znode节点执⾏了更新操作。⽽⼀个监视点(watch)表⽰⼀个与之关联的znode节点和事件类型组成的单次触发器(例如,znode节点的数据被赋值,或znode节点被删除)。当⼀个监视点被⼀个事件触发时,就会产⽣⼀个通知(notification)。通知是注册了监视点的应⽤客户端收到的事件报告的消息。当应⽤程序注册了⼀个监视点来接收通知,匹配该监视点条件的第⼀个事件会触发监视点的通知,并且最多只触发⼀次。
  2)监视点:客户端设置的每个监视点与会话关联,如果会话过期,等待中的监视点将会被删除。不过监视点可以跨越不同服务端的连接⽽保持,例如,当⼀个ZooKeeper客户端与⼀个ZooKeeper服务端的连接断开后连接到集合中的另⼀个服务端,客户端会发送未触发的监视点列表,在注册监视点时,服务端将要检查已监视的znode节点在之前注册监视点之后是否已经变化,如果znode节点已经发⽣变化,⼀个监视点的事件就会被发送给客户端,否则在新的服务端上注册监视点。
  监视点有两种类型:数据监视点和⼦节点监视点。
a.创建、删除或设置⼀个znode节点的数据都会触发数据监视点,exists和getData这两个操作可以设置数据监视点。
b.只有getChildren操作可以设置⼦节点监视点,这种监视点只有在znode⼦节点创建或删除时才被触发。
⼀旦设置监视点就⽆法移除。要想移除⼀个监视点,只有两个⽅法,⼀是触发这个监视点,
⼆是使其会话被关闭或过期。
  3)通知:为了解决客户端的轮询,ZK选择了基于通知(notification)的机制:客户端向ZooKeeper注册需要接收通知的znode,通过对znode设置监视点(watch)来接收通知。监视点是⼀个单次触发的操作,意即监视点会触发⼀个通知。为了接收多个通知,客户端必须在每次通知后设置⼀个新的监视点。

    当使⽤通知机制时,还有⼀些需要知道的事情。因为通知机制是单次触发的操作,所以在客户端接收⼀个znode变更通知并设置新的监视点时,znode节点也许发⽣了新的变化(不要担⼼,你不会错过状态的变化)。
  让我们看⼀个例⼦来说明它到底是怎么⼯作的。假设事件按以下顺序发⽣:

    1.客户端c 1 设置监视点来监控/tasks数据的变化。
    2.客户端c 1 连接后,向/tasks中添加了⼀个新的任务。
    3.客户端c 1 接收通知。
    4.客户端c 1 设置新的监视点,在设置完成前,第三个客户端c 3 连接后,向/tasks中添加了⼀个新的任务。
  客户端c 1 最终设置了新的监视点,但由c 3 添加数据的变更并没有触发⼀个通知。为了观察这个变更,在设置新的监视点前,c 1 实际上需要读取节点/tasks的状态,通过在设置监视点前读取ZooKeeper的状态,最终,c 1就不会错过任何变更。
  通知机制的⼀个重要保障是,对同⼀个znode的操作,先向客户端传送通知,然后再对该节点进⾏变更。如果客户端对⼀个znode设置了监视点,⽽该znode发⽣了两个连续更新。第⼀次更新后,客户端在观察第⼆次变化前就接收到了通知,然后读取znode中的数据。

    ZooKeeper可以定义不同类型的通知,这依赖于设置监视点对应的通知类型。客户端可以设置多种监视点,如监控znode的数据变化、监控znode⼦节点的变化、监控znode的创建或删除。为了设置监视点,可以使⽤任何API中的调⽤来读取ZooKeeper的状态,在调⽤这些API时,传⼊⼀个watcher对象或使⽤默认的watcher。

 思考题:单次触发是否会丢失事件?
答案是肯定的。⼀个应⽤在接收到通知后,注册另⼀个监视点时,可能会丢失事件。但是丢失事件通常并不是问题,因为任何在接收通知与注册新监视点之间的变化情况,均可以通过读取ZooKeeper的状态信息来获得。假设⼀个从节点接收到⼀个新任务分配给它的通知。为了接收新任务,从节点读取任务列表,如果在通知接收后,又给这个从节点分配了更多的任务,在通过getChildren调⽤获取任务列表时会返回所有的任务。同时调⽤getChildren时也可以设置新的监视点,从⽽保证从节点不会丢失任务。实际上,将多个事件分摊到⼀个通知上具有积极的作⽤,⽐如,应⽤进⾏⾼频率的更新操作时,这种通知机制⽐每个事件都发送通知更加轻量化。举个例⼦,如果每个通知平均捕获两个事件,我们为每个事件只产⽣了0.5个通知,⽽不是每个事件1个通知。

5.6 仲裁模式
server.n=127.0.0.1:3333:3334
3333:3334 为TCP端口号,分别用于仲裁通信和群首选举;
5.7 简单的负载均衡:
  
/bin/zkCli.sh -server 127.0.0.1:2181 127.0.0.1:2182 127.0.0.1:2183
客户端以随机顺序连接到连接串中的服务,这样可以用zk来实现一个简单的负载均衡,不过客户端无法指定优先选择的服务器进行连接。



参看书籍:Zookeeper 分布式过程.pdf 如有需要欢迎留言!

posted @ 2020-09-04 19:23  爱笑的berg  阅读(1081)  评论(0编辑  收藏  举报