zoukankan      html  css  js  c++  java
  • 基于Curator的zookeeper介绍和使用

    最好的学习方式当然是实践与理论相结合。在接收开发任务前正好在研究zookeeper。嗯,喜好模型的我,自然是研究zookeeper的理论部分,在此推荐书籍《从PAXOS到ZOOKEEPER分布式一致性原理与实践》。印象及其深刻的一幕在此发生,因研究完上述书籍,对zookeeper的原理十分清楚,便用了一个下午的时间完成了zookeeper模块的实现,当时主管一度怀疑,特地翻了一遍我的代码~~ 呵呵呵,好吧,可能在开发方面我看起来不像是个靠谱的人。

    然而 ,这种情况也是极少见的,即研究完一个技术后边能在工作中实践。在工作中更多的情况是需要到了某技术,然后一遍学习一遍实践,以及事后总结。

    回归主题O(∩_∩)O~

    在此澄清一个概念:介绍分布式一致性算法的是Paxos,zookeeper是基于ZAB协议,即一种崩溃可恢复的原子消息广播算法。

    9月份时,基于手上的这本《从PAXOS到ZOOKEEPER...》, 出现了如下几个疑惑:

      1. PAXOS是什么

      2. zookeeper和PAXOS是什么关系

      3. zookeeper的应用场景

      4. zk如何在第3点中应用场景中使用。

      5. 实现,基于Curator的Java的实现

    如上 我们就以这个顺序来介绍。

    一、PAXOS

    用一句话来解释Paxos是什么,那就是消息传递的一致性算法。注意,我们是基于分布式系统的应用场景来介绍的,在分布式系统中,当机器接A收到消息a时,在各个特殊情况都有可能发生的情况下,如何让系统中的机器B,机器C...也都能准确地接收到消息a,这就是一致性算法的目的。

    我们现在明确一下概念。

    节点一词通常可以表达两个概念,机器节点和数据节点。具体看情景。在此所述的分布式系统中,机器A,机器B..通常就被称为节点,机器节点。

    节点间的通信有两种模式:共享内存和消息传递。本文所介绍的Paxos便是基于消息传递的一致性算法。

    好,那么Paxos具体是什么呢?

    Leslie Lamport,莱斯利·兰伯特, 他是谁? who cares!  但是如果你用过活着知道Latex,就不是这份面孔了,→_→。。就是Latex的La,就是那个,因为嫌弃其他编辑器不好使,并且排版不漂亮的问题,自己搞出Latex的那位大牛。本人很是佩服。

    这位大牛先后提出了两个场景,“拜占庭将军问题”(描述请找度娘),后因为

      1. 分布式系统处于同一个局域网,消息被篡改的可能性极小

      2. 可以校验算法解决消息不完整问题

    重新提出"兼职会议"来描述一致性算法需要解决的问题。

    1. 场景

    “兼职会议”:小岛采用会议形式来通过法令,议员通过信使传递消息,议员和信使都是兼职的,随时可以离开会议厅且信使可能重复传递消息,这种情况下会议需要法令能够正确产生和不出现冲突。

    2. PAXOS详解

    三种角色:Proposer / Acceptor / Learner

    2.1 提案的选定

    Acceptor接收的第一个提案作为选定的提案,那么只有一个Acceptor的缺陷便是Accpetor挂了后整个系统将无法工作。

    所以解决方案是有多个Acceptor可以批准提案:

    当足够多的Acceptor批准同一个提案时,这个提案就被选定。足够多个Acceptor是多少个呢?包含了整个Acceptor集合的大多数成员。任意两个包含大多数成员的子集必有一个公共成员。即半数以上

    P1:一个Acceptor必须批准他收到的第一个提案

    P2:如果编号为M0,Value为V0的提案配(即[M0,V0])被选定了,那么所必编号M0高,且被选定的提案其Value必须也是V0

    一个提案被选定需要半数以上的Acceptor批准的需求暗示一个Acceptor必须能够批准不止一个提案。需要全局编号来标识每一个被Acceptor批准的提案。

      [全局编号,Value]表示一个提案,

    根据P2 在当[M0,V0]被选定时,提案者Proposer生成的提案必为[M1,V0],[M2.V0],...M2>M1>M0

    2.1.1提案的生成

    Proposer选择一个新的提案编号Mn, 然后向某个Acceptor集合的成员发送请求,要求Acceptor作出如下回应:

      1. 不再批准任何编号小于Mn的提案

      2. 如果已批准过提案,那么向Proposer反馈当前该Acceptor已经批准的编号小于Mn但为最大编号的那个提案的值。

    Proposer收到来自半数以上Acceptor的响应结果,可以产生提案[Mn,Vn]

      情况1. 响应中包含提案 Vn的值来自于响应中编号最大的提案的Value值. 

      情况2. 响应中不包含提案 Vn值由Proposer任意选择

    2.1.2Acceptor批准提案

    一个Acceptor只要尚未响应过任何编号大于Mn的Prepare请求,那么他就可以接受这个编号为Mn的提案。

    ps Acceptor可能会接收来自Proposer的两种请求,Prepare请求和Accept请求

    2.2提案的获取

     让Learner获取提案有一下三种方案:

      1. Acceptor批准了一个提案,将该提案发送给所有Learner, 通信次数是Acceptor和Learner个数的乘积

      2. 选取主Learner, Acceptor会将得到批准的提案发送给主Learner,再由其同步给其他Learner

      3. 将主learner扩大范围即 Acceptor将批准的提案发送给一个特定的Learner集合

    2.3 优化

    2.3.1 安全性(Safety)

      1.只有被提出的提案才能被选定

      2.只有一个值被选定

      3.如果某个进程任务某个天啊被选定了,那么这个提案必须是真的被选定的那个

    2.3.2 活性(Liveness)

    两个Proposer依次提出编号递增的议案,但最终都无法被选定:

    P1提出[M0,V0],Acceptor响应Prepare请求, 此时P2提出[M1,V1] ,Acceptor响应Prepare请求,同意不再批准编号小于M1的提案。

    此时P1向Acceptor发出Accept请求时被拒,因此P1重新发出[M2,V2]提议后,向Accept发出Prepare请求,Acceptor响应同意不再批准编号小于M2的提案。

    此时P2向Acceptor发出Accept请求时被拒...依次类推陷入死循环。

    以上情况的解决方法是一个主Proposer并规定只有主Proposer能够提出议案。

    二、zookeeper和PAXOS是什么关系

    1. zookeeper相关概念

      1. 集群角色:分布式系统中最典型的集群模式是Master/Slave. 而由3~5台机器便可搭建成一个集群的zookeeper,其集群角色引入Leader,Follower和Observer. 

      2. 会话Session:客户端与服务器之间的一个TCP长连接,通过心跳检测保持有效会话,可向zk发送请求接受响应接收Wathch事件通知。在sessionTimeout内重新连接上集群中的任意一台服务器,之前的会话仍有效.

      3. 数据节点:存储数据内容,保存属性信息。  

      4. 版本:每个ZNode都会维护一个Stat的数据结构,保存三个数据版本(Znode的版本version,ZNode子节点的版本cversion,ZNode的ACL版本aversion)

      5. Watcher:事件监听器

      6. ACL:权限监控策略,Create,Read,Write,Delete,Admin .

    2. ZAB协议

    ZAB协议(zookeeper Atomic Broadcast)支持崩溃恢复的原子广播协议。

    ZAB协议包括两种基本模式:崩溃恢复和消息广播

    核心:定义对于会改变zookeeper服务器数据状态的事务请求的处理方式。

    2.1 如何处理:

    (消息广播)(基于有FIFO特性的TCP协议进行网络通信以保证信息广播过程中接收发送的顺序性)所有事务请求必须由一个全局唯一的服务器(即leader)来协调。负责将客户端事务请求转换成一个事务Proposal(提议)。并将该Proposal分发给集群中所有的Follower服务器。Leader服务器会为每一个Follower服务器各自分配一个单独的队列,然后将需要广播的事务Proposal依次放入列队中去并根据FIFO策略进行消息发送

    所有的Follower服务器要么正常反馈Leader提出的事务Proposal,或者抛弃Leader服务器。

    Leader服务器等待所有Follower服务器的反馈,超过半数进行正反馈,Leader会想所有Follower分发Commit消息,将Proposal进行提交。

    Leader服务器崩溃退出进入崩溃恢复模式(崩溃恢复)

    R1:ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交。

    R2:ZAB协议需要确保丢弃只在Leader服务器上被提出的事务

    步骤1.所以Leader选举算法要求Leaders服务器拥有集群中所有机器最高编号(ZXID最大)的事务Proposal

    步骤2.数据同步。 Leader服务器需要确保所有的Follower服务器能够接收到每一条事务Proposal,并且能够正确地将所有已经提交了的事务Proposal应用到内存数据库中去。

    (如何操作)Leader为每个Follower服务器准备一个队列,并将那些没有被Follower服务器同步的事务以Proposal消息的形式逐个发送给Follower服务器。及每个Proposal后面紧接再发送一个Commit消息。数据同步后Leader才会将该Follower加入到真正可用的Follower列表中。

    2.2 深入ZAB:

    系统模型:

    一组进程π,进程子集Q :Q1交Q2的集合不为空。

    两个基本特性:

    完整性即Pj收到消息m,说明Pi发送了消息m

    前置性即m1是m2的前置消息,进程Pj收到m2前必接收到m1

    可划分为3个阶段:发现(Leader),同步(数据),广播(事务)

    发现(LOOKING,准Leader):

    1. 所有Follower将自己最后接收的事务Proposal的epoch发送给准Leader(准Leader又是如何选出来的????)

    2. 准Leader接收到过半的Follower的CEPOCH(Fp)消息,取最大的epoch值+1作为新的NEWEPOCH(e’)消息返回给这些过半的Follower。

    3. Follower接收到来自准Leader L的NEWEPOCH(e’)消息后确认当前的CEPOCH(Fp)值小于e',并赋值,向准Leader反馈Ack消息。

    Leader收到过半确认的Ack后,成为正式Leader,并从过半的Follower中选取一个作为初始化事务集合I(e')

    同步(FOLLOWING,准Leader):

    1. Leader 将e'和I(e')用NEWLEADER(e',Ie')消息的形式发送给所有Quorum中的Follower.(Quorum是什么????集群?

    2. Follower收到NEWLEADER(e',Ie')消息后,若CEPOCH=e’则执行事务应用操作,任给<v,z>属于Ie',Follower都会接受<e',<v,z>>,并反馈给Leader自己已执行完事务Proposal;若CEPOCH不为e’,则说明Follower在上一轮或者更上一轮,不参与本轮同步。

    3.Leader接受过半Follower对于NEWLEADER(e',Ie')消息后,向所有Follower发送Commit命令。

    4.Follower接收到Commit消息后,依次处理并提交Ie''中未处理的事务。

    广播(LEADING,真正的Leader):正式可以接收客户端新的请求

    1.Leader接收到客户端新的事务请求后,生成Proposal。并根据ZXID的顺序依次向所有Follower发送提案<e',<v,z>>,此时的epoch(Z)=e'。

    2.Follower根据接收的先后顺序依次处理Proposal,并追加到hf中去。再反馈给Leader.

    3.Leader收到过半Follower针对事务Proposal<e',<v,z>>的Ack消息后,发送Commit<e',<v,z>>给所有的Follower.

    4.Follower接收到Commit<e',<v,z>>消息后,便提交Proposal<e',<v,z>>

    3. ZAB与Paxos

    ZAB: 构建一个高可用的分布式数据主备系统

    PAXOS: 构建一个分布式的一致性状态机系统 

     三、 zookeeper的应用场景

    数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁、分布式列队

    四、 如何应用

    还没想好如何介绍。。。。

    五、 应用

    糟糕,有些虎头蛇尾  ,  真的是不想写了。。。。。。。。。。。先粘一波 后续继续

    Curator是Netflix公司开源的一个ZooKeeper client library,用于简化ZooKeeper客户端编程。Curator包含了以下几个包:

    curator-framework:对zookeeper的底层api的一些封装

    curator-client:提供一些客户端的操作,例如重试策略等

    curator-recipes:封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等

    使用方法:

    1. 连接zookeeper,

    RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

    CuratorFramework client =

    CuratorFrameworkFactory.newClient(connectionInfo,5000,3000,retryPolicy);

    newClient静态工厂方法包含四个主要参数:

    参数名

    说明

    connectionString

    connectionString    服务器列表,格式host1:port1,host2:port2,...

    retryPolicy

    重试策略,内建有四种重试策略,也可以自行实现RetryPolicy接口

    sessionTimeoutMs

    会话超时时间,单位毫秒,默认60000ms

    connectionTimeoutMs

    连接创建超时时间,单位毫秒,默认60000ms

    1. 启动客户端

    当创建会话成功后,得到client实例,可用start()启动客户端

    client.start();

    1. 创建数据节点

    Zookeeper的节点创建模式:

    •   PERSISTENT:持久化

    •   PERSISTENT_SEQUENTIAL:持久化并且带序列号

    •   EPHEMERAL:临时

    •  EPHEMERAL_SEQUENTIAL:临时并且带序列号

    创建一个节点,指定创建模式(临时节点),附带初始化内容,并且自动递归创建父节

    client.create()

    .creatingParentContainersIfNeeded()

    .withMode(CreateMode.EPHEMERAL)

    .forPath("path","init".getBytes());

    1. 删除节点

    删除一个节点,此方法只能删除叶子节点,否则会抛出异常。

    client.delete().forPath("path");

    删除一个节点,并且递归删除其所有的子节点

    client.delete().deletingChildrenIfNeeded().forPath("path");

    删除一个节点,强制指定版本进行删除

    client.delete().withVersion(1001).forPath("path");

    删除一个节点,强制保证删除

    client.delete().guaranteed().forPath("path");

    1. 读取节点数据

    读取一个节点的数据内容,此方法返的返回值是byte[ ];

    client.getData().forPath("path");

    1. 更新数据节点

    更新一个节点的数据内容

    client.setData().forPath("path","data".getBytes());

    1. 检测节点存在

    检查节点是否存在

    client.checkExists().forPath("path");

    1. 监听

    Path Cache用来监控一个ZNode的子节点. 当一个子节点增加, 更新,删除时, Path Cache会改变它的状态,并包含最新的子节点, 子节点的数据和状态,而状态的更变将通过PathChildrenCacheListener通知。

    通过下面的构造函数创建Path Cache:

    public PathChildrenCache(CuratorFramework client, String path, boolean cacheData)

    想使用cache,必须调用它的start方法,使用完后调用close方法。 可以设置StartMode来实现启动的模式,

    StartMode有下面几种:

    1.   NORMAL:正常初始化。

    2.   BUILD_INITIAL_CACHE:在调用start()之前会调用rebuild()。

    3.   POST_INITIALIZED_EVENT: 当Cache初始化数据后发送一个PathChildrenCacheEvent.Type#INITIALIZED事件

    public void addListener(PathChildrenCacheListener listener)可以增加listener监听。

  • 相关阅读:
    洛谷 P1074 靶形数独 Label:search 不会
    TYVJ P3522 &&洛谷 P1135 奇怪的电梯 Label:bfs
    洛谷 P1160 队列安排 Label:链表 数据结构
    uestc 1073 秋实大哥与线段树 Label:线段树
    TYVJ P3407 佳佳的魔法照片 Label:语文很重要 语文很重要 语文很重要
    TYVJ P1103 多项式输出 Label:模拟 有点儿坑
    A+B Problem 详细解答 (转载)
    如何批量修改文件名
    c++ 在windows下获取时间和计算时间差的几种方法总结
    SQL Server 2008在Windows 10上不支持
  • 原文地址:https://www.cnblogs.com/Zhouwl/p/10090693.html
Copyright © 2011-2022 走看看