• Zookeeper 简介


     

    1. 基本介绍

    1.1. 基本概念

      Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。 

      它的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

    1.2. 设计目标

      ZooKeeper允许分布式进程通过共享的层次结构命名空间进行相互协调,这与标准文件系统类似。

      名称空间由ZooKeeper中的数据寄存器组成称为znode,这些类似于文件和目录。

      与为存储设计的典型文件系统不同,ZooKeeper数据保存在内存中,这意味着ZooKeeper可以实现高吞吐量低延迟

    1.3. 主要特点

      最终一致性:为客户端展示同一视图,这是 ZooKeeper 最重要的性能。

      可靠性:如果消息被一台服务器接受,那么它将被所有的服务器接受。

      实时性:ZooKeeper 不能保证两个客户端同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

      等待无关(wait-free):慢的或者失效的 client 不干预快速的client的请求。

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

      顺序性:对于所有Server同一消息发布顺序一致

    1.4. 分布式相关概念

    1.4.1. CAP

      一致性 Consistency

        任何操作都是原子的.发生在后面的事件可以看到前面发生事件的结果;

        注意:这里的一致性是指**强一致性**

      可用性 Availablity

        对于用户的每一个请求**在有限时间内****返回结果**.

        注意:

            1. "有限时间内": 是指 对于用户的请求,系统必须存在合理的响应时间,否则用户便会对系统感到失望;

            2. "返回结果":是指 响应结果能够正常反映请求的处理结果,即成功或失败,而不是让用户困惑的结果.

      分区容错性 Partition Tolerance

        系统在遇到任何网络故障时,仍能对外提供可用性和一致性服务,除非整个网络发生故障.

       一个分布式系统无法同时满足以上三个需求,因此在实际运用时,我们就要抛弃其中一项.

       CAP定理应用:

         1. 放弃P:放弃P就意味着放弃了扩展性.就是把所有数据放在一个分布式节点上.

         2. 放弃A:系统遇到故障时,在等待时间内系统无法对外提供正常服务,即不可用.

         3. 放弃C:放弃强一致性,而保持数据的最终一致性.引入时间窗口概念.

       对于分布式系统而言,网络问题是必定会出现的异常情况,因为P是一个分布式系统必须面对和解决的问题.

       所以往往要根据业务权衡CA之间的选择.

    1.4.2. ZooKeeper提供的一致性服务

      ZooKeeper从以下几点保证了数据的一致性

      顺序一致性:来自任意特定客户端的更新都会按其发送顺序被提交保持一致。也就是说,如果一个客户端将Znode z的值更新为a,在之后的操作中,它又将z的值更新为b,则没有客户端能够在看到z的值是b之后再看到值a(如果没有其他对zk的更新)。

      原子性:每个更新要么成功,要么失败。这意味着如果一个更新失败,则不会有客户端会看到这个更新的结果。

      单一系统映像:一个客户端无论连接到哪一台服务器,它看到的都是同样的系统视图。这意味着,如果一个客户端在同一个会话中连接到一台新的服务器,它所看到的系统状态不会比 在之前服务器上所看到的更老。当一台服务器出现故障,导致它的一个客户端需要尝试连接集合体中其他的服务器时,所有滞后于故障服务器的服务器都不会接受该 连接请求,除非这些服务器赶上故障服务器。

      持久性:一个更新一旦成功,其结果就会持久存在并且不会被撤销。这表明更新不会受到服务器故障的影响。

      实时性:在特定的一段时间内,客户端看到的系统需要被保证是实时的(在十几秒的时间里)。在此时间段内,任何系统的改变将被客户端看到,或者被客户端侦测到。 

    1.4.3. CAP理论来分析ZooKeeper

      在ZooKeeper保证的是CP

      分析:可用性(A:Available

      不能保证每次服务请求的可用性

      任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper不能保证服务可用性。

      进行leader选举时集群都是不可用

      在使用ZooKeeper获取服务列表时,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。所以说,ZooKeeper不能保证服务可用性。

    1.4.4. BASE

      基本可用:Basic Available

        分布式系统在出现故障时,允许**损失部分可用性**,但是系统还是可用的.

      弱状态:Soft State

        和ACID强状态相对应,是指系统中允许存在的中间状态不会影响系统的整体可用性

      最终一致性:Eventually Consistent

        系统中的数据,经过同步之后最终能够达到一个一致的状态.最终一致性的变种:

        因果一致性:

        读己一致性:

           会话一致性:

        单调读一致性:

        单调写一致性:

      BASE理论是对CAP**一致性和可用**性的权衡总结.

    2. 基本概念

    2.1. 基本架构

      客户端随机连接集群中的任何一台 server

      集群内所有的 server 基于 Zab(ZooKeeper Atomic Broadcast)协议通信

      集群内部根据算法自动选举出 leader, 负责向 follower 广播所有变化消息

      集群中每个follower 都和 leader 通信

        follower 接收来自 leader 的所有变化消息,保存在自己的内存中

        follower 转发来自客户端的写请求给 leader

        客户端的读请求会在 follower 端直接处理,无需转发给 leader

      ZooKeeper 启动时,将从实例中选举一个 leaderLeader 负责处理数据更新等操作,一个更新操作成功的标志是当且仅当大多数Server在内存中成功修改数据。每个Server 在内存中存储了一份数据。

      Zab协议包含两个阶段:leader election阶段和Atomic Brodcast阶段。

        a) 集群中将选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给leader,并通过brodcast将所有的更新告诉给follower

        b) leader崩溃或者leader失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器都恢复到一个正确的状态。

        c) leader被选举出来,且大多数服务器完成了 和leader的状态同步后,leadder election 的过程就结束了,就将会进入到Atomic brodcast的过程。

        d) Atomic Brodcast同步leaderfollower之间的信息,保证leaderfollower具有形同的系统状态。

    三个端口:

      客户端连接ZooKeeper集群使用的监听端口号

      leaderfollower之间数据同步使用的端口号

      leader选举专用的端口号

    2.2. 角色

      leader:负责投票的发起和决议,更新系统状态

      follower:接收客户端请求(写请求则转发给leader)并返回客户端结果,选举过程中参与投票(follower的数量影响选举的时间长短)

      observer:接收客户端请求(写请求则转发给leader)并返回客户端结果,选举过程中不参与投票,只同步leader的状态,目的是扩展系统,提高读取速度

    2.3. 数据模型

      基于树形结构的命名空间,与文件系统类似

      节点(znode)都可以存储数据,可以有子节点

      节点不支持重命名

      数据大小不超过1MB(可配置)

      数据读写保持完整性

    2.4. Znode类型

      Zookeeper有四种类型的节点:

      PERSISTENT

      PERSISTENT_SEQUENTIAL

      EPHEMERAL

      EPHEMERAL_SEQUENTIAL

    2.4.1. Persistent /Ephemeral

      Persistent(持久化节点)节点生命周期和session无关, 只能显式删除

      Ephemeral(临时节点)节点在客户端session结束或超时后自动删除

    2.4.2. Sequential /non-sequential

      Non-sequential节点不能有重名

      Sequential节点

        创建时可重名

        实际生成节点名末尾自动添加一个10位长度,左边以0填充的单递增数字,如下所示:

    2.5. Session

      客户端和 server 间采用长连接

      连接建立后, server生成 session id(64)返还给客户端

      客户端定期发送 ping 包来检查和保存和 server 的连接

      一旦 session 结束或超时,所有 ephemeral节点会被删除

      客户端可根据情况设置合适的 session 超时时间

    2.6. Watcher

      Watch 是客户端安装在 server 的事件监听方法

      当监听的节点发生变化, server 将通知所有注册的客户端

      客户端使用单线程对所有时间按顺序同步回调

      触发回调条件:

        客户端连接,断开连接

        节点数据发生变化

        节点本身发生变化

      注意:

        Watch 是单次的,每次触发后会被自动删除

        如果需要再次监听时间,必须重新安装 Watch

      Watcher的创建和触发规则:

       

    2.7. 数据同步

      在开始数据同步之前,Leader服务器会进行数据同步初始化,首先会从ZooKeeper的内存数据库中提取出事务请求对应的提议缓存队列(下面我们用提议缓存队列来指代该队列):proposals,同时完成对以下三个ZXID值的初始化。

      peerLastZxid:该Learner服务器最后处理的ZXID

      minCommittedLogLeader服务器提议缓存队列committedLog中的最小ZXID

      maxCommittedLogLeader服务器提议缓存队列committedLog中的最大ZXID

       ZooKeeper集群数据同步通常分为四类,分别是直接差异化同步(DIFF同步)、先回滚再差异化同步(TRUNC+DIFF同步)、仅回滚同步(TRUNC同步)和全量同步(SNAP同步)。

      在初始化阶段,Leader服务器会优先初始化以全量同步方式来同步数据——当然,这并非最终的数据同步方式,在以下步骤中,会根据LeaderFollower服务器之间的数据差异情况来决定最终的数据同步方式。

    3. 基本原理

    3.1. 工作模式

      ZooKeeper有三种工作模式

      Standalone:单点模式,有单点故障问题。

      伪分布式:在一台机器同时运行多个ZooKeeper实例,仍然有单点故障问题,当然,其中配置的端口号要错开的,适合实验环境模拟集群使用。

      完全分布式:在多台机器上部署ZooKeeper集群,适合线上环境使用

    3.2. 使用方式

    3.2.1. 命令行

    zookeeper根目录下启动zookeeper客户端连接zookeeperserver端进行操作。

    1. 启动客户端工具,默认连接 localhost:2181

        bin/zkCli.sh

    1. 基本命令

        执行 help 命令,显示可执行的命令行操作。如下所示:

    3.2.2. Java API

      本次使用的zookeeper的服务端版本为 3.4.9Java 依赖的 curator版本必须为2.x版本

      Demo如下:

    4. 典型的应用场景

    4.1. 统一命名服务(Name Service

      在ZooKeeper的树形结构下你可以创建一个统一的不重复的命名,比如create创建一个节点即可,再创建一个相同名称的节点是不允许的。

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

        a)类似于域名与ip之间对应关系,ip不容易记住,而域名容易记住。

        b)通过名称来获取资源或服务的地址,提供者等信息。

      2、按照层次结构组织服务/应用名称。

        a)可将服务名称以及地址信息写到ZooKeeper上,客户端通过ZooKeeper获取可用服务列表类。

    4.2. 配置管理(Configuration Management

      1、分布式环境下,配置文件管理和同步是一个常见问题。

        a)一个集群中,所有节点的配置信息是一致的,比如 Hadoop 集群。

        b)对配置文件修改后,希望能够快速同步到各个节点上。

      2、配置管理可交由ZooKeeper实现。

        a)可将配置信息写入ZooKeeper上的一个Znode

        b)各个节点监听这个Znode

        c)一旦Znode中的数据被修改,ZooKeeper将通知各个节点。

    4.3. 集群管理(Group Membership

      Zookeeper 不仅能够帮你维护当前的集群中机器的服务状态,而且能够帮你选出一个总管,让这个总管来管理集群,这就是 Zookeeper 的另一个功能 Leader Election

      它们的实现方式都是在 Zookeeper上创建一个 EPHEMERAL 类型的目录节点,然后每个 Server 在它们创建目录节点的父目录节点上调用 getChildren(String path, boolean watch) 方法并设置 watch true,由于是 EPHEMERAL 目录节点,当创建它的 Server 死去,这个目录节点也随之被删除,所以 Children 将会变化,这时 getChildren上的 Watch 将会被调用,所以其它 Server 就知道已经有某台 Server 死去了。新增 Server 也是同样的原理。

      Zookeeper 如何实现 Leader Election,也就是选出一个 Master Server。和前面的一样每台 Server 创建一个EPHEMERAL 目录节点,不同的是它还是一个SEQUENTIAL 目录节点,所以它是EPHEMERAL_SEQUENTIAL 目录节点。之所以它是 EPHEMERAL_SEQUENTIAL 目录节点,是因为我们可以给每台 Server 编号,我们可以选择当前是最小编号的 Server Master,假如这个最小编号的 Server 死去,由于是 EPHEMERAL 节点,死去的 Server 对应的节点也被删除,所以当前的节点列表中又出现一个最小编号的节点,我们就选择这个节点为当前 Master。这样就实现了动态选择 Master,避免了传统意义上单 Master 容易出现单点故障的问题。

    4.4. 分布式锁Locks

      处于不同节点上不同的服务,它们可能需要顺序的访问一些资源,这里需要一把分布式的锁。

      分布式锁具有以下特性:

        1、ZooKeeper是强一致的。比如各个节点上运行一个ZooKeeper客户端,它们同时创建相同的Znode,但是只有一个客户端创建成功。

        2、实现锁的独占性。创建Znode成功的那个客户端才能得到锁,其它客户端只能等待。当前客户端用完这个锁后,会删除这个Znode,其它客户端再尝试创建Znode,获取分布式锁。

        3、控制锁的时序。各个客户端在某个Znode下创建临时Znode,这个类型必须为CreateMode.EPHEMERAL_SEQUENTIAL,这样该Znode可掌握全局访问时序。

    4.5. 队列管理

      1.同步队列

      当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。
      队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型。
      同步队列用 Zookeeper 实现的实现思路如下:
      创建一个父目录 /synchronizing,每个成员都监控标志(Set Watch)位目录 /synchronizing/start 是否存在,然后每个成员都加入这个队列,加入队列的方式就是创建 /synchronizing/member_i 的临时目录节点,然后每个成员获取 / synchronizing 目录的所有目录节点,也就是 member_i。判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /synchronizing/start 的出现,如果已经相等就创建 /synchronizing/start

      2. FIFO队列:

      实现的思路也非常简单,就是在特定的目录下创建 SEQUENTIAL 类型的子目录 /queue_i,这样就能保证所有成员加入队列时都是有编号的,出队列时通过 getChildren( ) 方法可以返回当前所有的队列中的元素,然后消费其中最小的一个,这样就能保证 FIFO

    ---恢复内容结束---

  • 相关阅读:
    冒泡排序及优化
    Map的三种遍历
    抽象类以及接口的异同
    安卓仿制新浪微博(一)之OAuth2授权接口
    安卓handler.post问题
    Git——版本控制器概述
    Linux概述及简单命令
    JBoss7配置-支持IPv4和IPv6双栈环境
    作用域public,private,protected,以及不写时的区别
    UML类图画法及类之间几种关系
  • 原文地址:https://www.cnblogs.com/virgosnail/p/11545790.html
Copyright © 2020-2023  润新知