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


    1、简介:

      ZooKeeper 是一个分布的、开源的协调服务,它主要是用来解决分布式应用中经常遇到的一些数据管理问题。统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。

    2、ZooKeeper 目标:

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

    3、ZooKeeper 工作方式:

      本身可以以 Standalone 模式安装运行,不过它的长处在于通过分布式 ZooKeeper 集群(一个Leader,多个 Follower),基于一定的策略来保证 ZooKeeper 集群的稳定性和可用性,从而实现分布式应用的可靠性。

      最新的版本可以在官网 http://zookeeper.apache.org/releases.html 来下载 zookeeper 的最新版本。

    4、ZooKeeper 特点:

      最终一致性:为客户端展示同一个视图,这是 ZooKeeper 里面一个非常重要的功能。
      可靠性:如果消息被一台服务器接受,那么它将被所有的服务器接受。
      实时性:ZooKeeper 不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用 sync() 接口。
      独立性:各个 Client 之间互不干预。
      原子性:更新只能成功或者失败,没有中间状态。
      顺序性:所有 Server,同一消息发布顺序一致。

    5、ZooKeeper 工作原理:

      每个 Server 在内存中存储了一份数据;
      ZooKeeper 启动时,将从实例中选举一个 Leader(Paxos 协议);
      Leader 负责处理数据更新等操作(Zab 协议);
      一个更新操作成功,当且仅当大多数 Server 在内存中成功修改数据。

      选举机制:

        全新集群选举:每个机器都给自己投票、投票数过半选举结束。myid 大的权重大。
        非全新集群选举:数据ID、服务器ID和逻辑时钟
        逻辑时钟小的选举结果被忽略,重新投票;
        统一逻辑时钟后,数据 ID 大的胜出;
        数据 ID 相同,服务器 ID 大的胜出。

      Paxos 协议:

        它是一个基于消息传递的一致性算法。Paxos 有一个前提:没有拜占庭将军问题。就是说 Paxos 只有在一个可信的计算环境中才能成立,这个环境是不会被入侵所破坏的。

        工作流程:提出提议,议员超过半数则提议生效,通知所有。顺序性提议编号。

      ZAB 协议:

      用来保障分布式数据一致性。ZAB 是一种支持崩溃恢复的消息广播协议,采用类似 2PC 的广播模式保证正常运行时性能,并使用基于 Paxos 的策略保证崩溃恢复时的一致性。

      ZAB 协议中节点存在四种状态:
        Leading:当前节点为集群 Leader,负责协调事务
        Following:当前节点为 Follower 在 Leader 协调下执行事务
        Looking:集群没有正在运行的 Leader, 正处于选举过程
        Observing:节点跟随 Leader 保存系统最新的状态提供读服务,但不参与选举和事务投票

      ZAB 协议的两种工作模式:
        广播模式:当集群正常运行过程中,Leader 使用广播模式保证各 Follower 节点的一致性
        恢复模式:集群启动或 Leader 崩溃时系统进入恢复模式,选举 Leader 并将集群中各节点的数据同步到最新状态

      ZooKeeper 集群中每个节点都会存储系统数据的完整副本,可以独立处理读请求。
      当 Follower 收到写请求时会将其转发给 Leader, Leader 为每个写请求分配唯一的全局有序的事务ID(Zookeeper Transaction Id, ZXID)。
      Leader 在广播模式下协调各 Follower 完成事务,并保证集群更新到一致的状态。

    6、ZooKeeper 角色:

      领导者(Leader):领导者负责进行投票的发起和决议,更新系统状态,处理写请求。
      跟随者(Follwer):Follower 用于接收客户端的读写请求并向客户端返回结果,在选主过程中参与投票。
      观察者(Observer):观察者可以接收客户端的读写请求,并将写请求转发给 Leader,但 Observer节点不参与投票过程,只同步 leader 状态,Observer 的目的是为了扩展系统,提高读取速度。
      客户端(Client):执行读写请求的发起方。

    7、ZooKeeper 的数据模型:

      树形结构的命名空间,与文件系统类似,层次化的目录结构,命名符合常规文件系统规范;
      数据大小不超过 1MB(可配置),数据读写要保证完整性;
      每个节点在 zookeeper 中叫做 znode,并且其有一个唯一的路径标识;
      节点(znode)都可以存数据,可以有子节点,节点不支持重命名;
      节点 Znode 可以包含数据和子节点(临时节点不能有子节点);
      Znode 中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据需带上版本;
      客户端应用可以在节点上设置监视器(Watcher)
      节点不支持部分读写,而是一次性完整读写;
      Znode 有两种类型,短暂的(ephemeral)和持久的(persistent)
      Znode 的类型在创建时确定并且之后不能再修改;
      短暂 znode 的客户端会话结束时,zookeeper 会将该短暂 znode 删除,短暂 znode 不可以有子节点;
      持久 znode 不依赖于客户端会话,只有当客户端明确要删除该持久 znode 时才会被删除;
      Znode 有 四 种 形 式 的 目 录 节 点 ,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL。

      节点属性:
        dataVersion(数据版本号)
        cversion(子节点版本号)
        ACLVersion
        cZxid(创建的事务id)
        mZxid(修改的事务id)
        ctime(节点创建时间)
        mtime(节点更新时间)
        ephemeralOwner(0x0:永久节点)

    8、数据发布与订阅:

      创建数据目录,订阅者初次启动的时候去 ZK 指定的节点获取相关的订阅信息;获取数据的同时,设置监听(监听节点数据的变化);一旦节点数据改变,触发监听,订阅者收到事件通知,获取数据,再次设置监听。
      注:统一管理的数据不能太大

    9、ZooKeeper 主要应用场景:

      (1)统一命名服务:

        分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务;
        类似于域名与 ip 之间对应关系,域名容易记住;
        通过名称来获取资源或服务的地址,提供者等信息;
        按照层次结构组织服务/应用名称;
        可将服务名称以及地址信息写到 ZooKeeper 上,客户端通过 ZooKeeper 获取可用服务列表类。

      (2)配置管理服务:

        分布式环境下,配置文件管理和同步是一个常见问题;
        一个集群中,所有节点的配置信息是一致的;
        对配置文件修改后,希望能够快速同步到各个节点上;
        配置管理可交由 ZooKeeper 实现,可将配置信息写入 ZooKeeper 的一个 znode 上,各个节点监听这个 znode ,一旦 znode 中的数据被修改,ZooKeeper 将通知各个节点。

      (3)集群管理:

        分布式环境中,实时掌握每个节点的状态是必要的;
        可根据节点实时状态作出一些调整;
        可交由 ZooKeeper 实现,可将节点信息写入 ZooKeeper 的一个 znode 上,监听这个 znode 可获取它的实时状态变化。

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

      (4)分布式通知和协调:

        分布式环境中,经常存在一个服务需要知道它所管理的子服务的状态;
        NameNode 须知道各 DataNode 的状态
        JobTracker 须知道各 TaskTracker 的状态
        心跳检测机制可通过 ZooKeeper 实现,信息推送可由 ZooKeeper 实现(发布/订阅模式)

      (5)分布式锁:保持独占、控制时序(序列化)

        Client 首先在 ZK 上指定的目录创建节点(节点是一个非序列化的临时节点),只能有一个创建成功,谁创建成功,谁就获得访问数据文件的权限,操作完成断开和 ZK 的连接,其他应用如果需要操作这个文件,就去监听这个目录是否存在。

      (6)分布式队列:

        两种队列:
        当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。
        队列按照 FIFO 先进先出方式进行入队和出队操作,例如实现生产者和消费者模型。(可通过分布式锁实现)

        同步队列:
        一个 job 由多个 task 组成,只有所有任务完成后,job 才运行完成。
        可为 job 创建一个/job 目录,然后在该目录下,为每个完成的 task 创建一个临时 znode,一旦临时节点数目达到 task 总数,则 job 运行完成。
        同步队列实现思路:
        创建一个父目录 /synchronizing,每个成员都监控标志(Set Watch)位目录 /synchronizing/start 是否存在,然后每个成员都加入这个队列,加入队列的方式就是创建 /synchronizing/member_i 的临时目录节点,然后每个成员获取 / synchronizing 目录的所有目录节点,也就是 member_i。判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /synchronizing/start 的出现,如果已经相等就创建/synchronizing/start。

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

    10、ZooKeeper 集群配置:

    (1)卸载 openjdk,安装 jdk 环境,配置环境变量

    (2)时间同步、防火墙处理

    (3)配置主机名到 ip 地址的映射

    [root@znode1 ~]# cat /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.100.31 znode1
    192.168.100.32 znode2
    192.168.100.33 znode3
    

    (4)三个节点分别:下载、解压 zookeeper-3.4.14.tar.gz 至安装目录(例:/usr/local/src/zookeeper-3.4.14)

    (5)创建同名软链接

    (6)修改 ZooKeeper 配置文件

    [root@znode1 ~]# cd /usr/local/src/zookeeper/conf/
    [root@znode1 conf]# cp zoo_sample.cfg zoo.cfg
    [root@znode1 conf]# vim zoo.cfg
    dataDir=/data/zookeeper
    clientPort=2181
    server.1=znode1:2888:3888    #心跳端口、选举端口
    server.2=znode2:2888:3888
    server.3=znode3:2888:3888
    
    # 参数说明
    tickTime=2000    #心跳间隔
    initLimit=10     #Follower 服务器初始化连接时最长能忍受多少个心跳时间间隔数
    syncLimit=5      # Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度
    dataDir          #Zookeeper保存数据的目录,默认情况下Zookeeper将写数据的日志文件也保存在这个目录里。
    clientPort       #这个端口就是客户端(应用程序)连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口接受客户端的访问请求。
    server.A=B:C:D   #A 为数字,表示第几号服务器;B 是这个服务器的 IP 地址或主机名映射;C 第一个端口用来集群成员的信息交换,表示这个服务器与集群中的 Leader 服务器交换信息的端口;D 是在 leader 挂掉时专门用来进行选举 leader 所用的端口。
    

     (7)在数据目录下创建 myid 文件

    [root@znode1 ~]# cat /data/zookeeper/myid 
    1
    

    (8)启动 ZooKeeper 集群

    [root@znode1 ~]# /usr/local/src/zookeeper/bin/zkServer.sh start
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    [root@znode1 ~]# jps    # 查看进程
    1397 Jps
    1372 QuorumPeerMain
    [root@znode1 ~]# /usr/local/src/zookeeper/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Mode: follower
    
    [root@znode2 ~]# /usr/local/src/zookeeper/bin/zkServer.sh start
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    [root@znode2 ~]# jps
    1291 Jps
    1260 QuorumPeerMain
    [root@znode2 ~]# /usr/local/src/zookeeper/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Mode: leader
    
    [root@znode3 ~]# /usr/local/src/zookeeper/bin/zkServer.sh start
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    [root@znode3 ~]# jps
    1330 QuorumPeerMain
    1355 Jps
    [root@znode3 ~]# /usr/local/src/zookeeper/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/src/zookeeper/bin/../conf/zoo.cfg
    Mode: follower
    

    (9)链接

    [root@znode1 ~]# /usr/local/src/zookeeper/bin/zkCli.sh    # 本地链接
    ......
    [zk: localhost:2181(CONNECTED) 0] 
    
    
    [root@znode2 ~]# /usr/local/src/zookeeper/bin/zkCli.sh -server znode3    # 远程链接
    ......
    [zk: znode3(CONNECTED) 0] 
    

    (9)简单命令

      创建:create [-se] [path]

        -s:序列化;-e:临时节点

      ls、get、ls2

    [zk: localhost:2181(CONNECTED) 0] ls /
    [zookeeper]
    [zk: localhost:2181(CONNECTED) 1] create /data 123
    Created /data
    [zk: localhost:2181(CONNECTED) 2] ls /
    [zookeeper, data]
    [zk: localhost:2181(CONNECTED) 3] get /data
    123
    cZxid = 0x400000005
    ctime = Fri May 22 18:23:24 CST 2020
    mZxid = 0x400000005
    mtime = Fri May 22 18:23:24 CST 2020
    pZxid = 0x400000005
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 3
    numChildren = 0
    [zk: localhost:2181(CONNECTED) 4] ls2 /data
    []
    cZxid = 0x400000005
    ctime = Fri May 22 18:23:24 CST 2020
    mZxid = 0x400000005
    mtime = Fri May 22 18:23:24 CST 2020
    pZxid = 0x400000005
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 3
    numChildren = 0
    

      删除:delete [-se] [path]

      rmr [path]

      quota

      setquota -n|-b [val] [path]

        n : 表示子节点的最大个数
        b : 表示数据值的最大长度
        val : 子节点最大个数或数据值的最大长度

      listquota

      delquota

      history

      redo

  • 相关阅读:
    typeid抛出异常的解释
    [原创]公平数的解法
    [原创]我的北大ACM POJ 1012解答
    [原创]我的PKU ACM POJ1029题解
    asp.net 单用户登录经典解决方案
    [转]SQL事务回滚的问题及其解决的方法
    获取json数据
    js中Date对象的用法
    解决刷新后回到顶部的问题
    C#获取客户端及服务器端主机信息
  • 原文地址:https://www.cnblogs.com/zyybky/p/12938908.html
Copyright © 2020-2023  润新知