• 03.Curator深入使用



    1.Apache Curator简介

        Curator提供了一套Java类库,可以更容易的使用ZooKeeper。ZooKeeper本身提供了Java Client的访问类,但是API太底层,不宜使用,易出错。Curator提供了三个组件。Curator client用来替代ZOoKeeper提供的类,它封装了底层的管理并提供了一些有用的工具。Curator framework提供了高级的API来简化ZooKeeper的使用。它增加了很多基于ZooKeeper的特性,帮助管理ZooKeeper的连接以及重试操作。Curator Recipes提供了使用ZooKeeper的一些通用的技巧(方法)。除此之外,Curator Test提供了基于ZooKeeper的单元测试工具。
        所谓技巧(Recipes),也可以称之为解决方案,或者叫实现方案,是指ZooKeeper的使用方法,比如分布式的配置管理,Leader选举等。
        Curator最初由Netflix的Jordan Zimmerman开发。20117月在github上基于Apache 2.0开源协议开源。之后发布了多个版本,并被广泛的应用。Curator作为Apache ZooKeeper天生配套的组件。ZooKeeper的Java开发者自然而然的会选择它在项目中使用。
    1.Curator组件概览
    • Recipes:通用ZooKeeper技巧("recipes")的实现. 建立在Curator Framework之上
    • Framework:简化zookeeper使用的高级. 增加了很多建立在zooper之上的特性. 管理复杂连接处理和重试操作
    • Utilities:各种工具类
    • Client:ZooKeeper本身提供的类的替代者。负责底层的开销以及一些工具
    • Errors:Curator怎样来处理错误和异常
    • Extensions:curator-recipes包实现了通用的技巧,这些技巧在ZooKeeper文档中有介绍。为了避免是这个包(package)变得巨大,recipes/applications将会放入一个独立的extension包下。并使用命名规则curator-x-name
    2.Maven/Artifacts
        Curator编译好的类库被发布到Maven Center中。Curator包含几个artifact. 你可以根据你的需要在你的项目中加入相应的依赖。对于大多数开发者来说,引入curator-recipes这一个就足够了。
    1. <dependency>
    2. <groupId>org.apache.curator</groupId>
    3. <artifactId>curator-client</artifactId>
    4. <version>2.9.0</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>org.apache.curator</groupId>
    8. <artifactId>curator-framework</artifactId>
    9. <version>2.9.0</version>
    10. </dependency>
    11. <dependency>
    12. <groupId>org.apache.curator</groupId>
    13. <artifactId>curator-recipes</artifactId>
    14. <version>2.9.0</version>
    15. </dependency>
    16. <dependency>
    17. <groupId>org.apache.curator</groupId>
    18. <artifactId>curator-x-discovery</artifactId>
    19. <version>2.9.0</version>
    20. </dependency>
    21. <dependency>
    22. <groupId>org.apache.curator</groupId>
    23. <artifactId>curator-examples</artifactId>
    24. <version>2.9.0</version>
    25. </dependency>

    2.Apache Curator Recipes

        Curator实现了 ZooKeeper recipes文档中列出的所有技巧(除了两段提交two phase commit)。下面介绍Recipes的使用,参考官网:http://curator.apache.org/curator-recipes/index.html
    1.Elections(选举)
    • Leader Latch - 在分布式计算中,leader选举是在几台节点中指派单一的进程作为任务组织者的过程。在任务开始前, 所有的网络节点都不知道哪一个节点会作为任务的leader或coordinator. 一旦leader选举算法被执行, 网络中的每个节点都将知道一个特别的唯一的节点作为任务leader
    • Leader Election - 初始的leader选举实现
    2.Locks()
    • Shared Reentrant Lock - 全功能的分布式锁。任何一刻不会有两个client同时拥有锁
    • Shared Lock - 与Shared Reentrant Lock类似但是不是重入的
    • Shared Reentrant Read Write Lock - 类似Java的读写锁,但是是分布式的
    • Shared Semaphore - 跨JVM的计数信号量
    • Multi Shared Lock - 将多个锁看成整体,要不全部acquire成功,要不acquire全部失败。release也是释放全部锁
    3.Barriers(障碍)
    • Barrier - 分布式的barriers。会阻塞全部的节点的处理,直到条件满足,所有的节点会继续执行
    • Double Barrier - 双barrier允许客户端在一个计算开始点和结束点保持同步。当足够的进程加入barrier,进程开始它们的计算,当所有的进程完成计算才离开
    4.Counters(计数器)
    • Shared Counter - 管理一个共享的整数integer.所有监控同一path的客户端都会得到最新的值(ZK的一致性保证)
    • Distributed Atomic Long - 尝试原子增加的计数器首先它尝试乐观锁.如果失败,可选的InterProcessMutex会被采用.不管是optimistic 还是 mutex,重试机制都被用来尝试增加值
    5.Caches(缓存)
    • Path Cache - Path Cache是用来监控子节点的。每当一个子节点“曾加、更新或删除”,将会触发事件,事件就是注册了的PathChildrenCacheListener实例执行。Path Cache的功能主要由PathChildrenCache类提供
    • Node Cache - 用于监控节点,当节点数据被修改或节点被删除,就会触发事件,事件就是注册了的NodeCacheListener实例执行。Node Cache的功能主要由NodeCache类提供
    6.Nodes(节点)
    • Persistent Ephemeral Node - 临时节点,可以通过连接或会话中断一个临时节点。
    7.Queues(队列)
    • Distributed Queue - 分布式的ZK队列
    • Distributed Id Queue - 分布式的ZK队列,它支持分配ID来添加到队列中的项目的替换版本
    • Distributed Priority Queue - 分布式优先级的ZK队列
    • Distributed Delay Queue - 分布式的延迟ZK队列
    • Simple Distributed Queue - 一个简单的替代自带的ZK分布式队列(Distributed Queue)
    其具体的实现示例,可参考官网:http://curator.apache.org/curator-recipes/index.html

    3.Apache Curator Framework

        Curator framework提供了高级API, 极大的简化了ZooKeeper的使用。 它在ZooKeeper基础上增加了很多特性,可以管理与ZOoKeeper的连接和重试机制。这些特性包括:
    • 自动连接管理:有些潜在的错误情况需要让ZooKeeper client重建连接和重试。Curator可以自动地和透明地处理这些情况
    • Cleaner API:简化原始的ZooKeeper方法,事件等 提供现代的流式接口
    1.产生Curator framework实例
        使用CuratorFrameworkFactory产生framework实例。 CuratorFrameworkFactory 既提供了factory方法也提供了builder来创建实例。CuratorFrameworkFactory是线程安全的。你应该在应用中为单一的ZooKeeper集群共享唯一的CuratorFramework实例。
        工厂方法(newClient())提供了一个简单的方式创建实例。Builder可以使用更多的参数控制生成的实例。一旦生成framework实例, 必须调用start方法启动它。应用结束时应该调用close方法关闭它。
    2.CuratorFramework API
        CuratorFramework 使用流程风格的接口。 代码胜于说教:
    1. client.create().forPath("/head", new byte[0]);
    2. client.delete().inBackground().forPath("/head");
    3. client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child", new byte[0]);
    4. client.getData().watched().inBackground().forPath("/test");
    CuratorFramework类重要方法说明
    • create()        开始创建操作, 可以调用额外的方法(比如方式mode 或者后台执行background) 并在最后调用forPath()指定要操作的ZNode
    • delete()        开始删除操作. 可以调用额外的方法(版本或者后台处理version or background)并在最后调用forPath()指定要操作的ZNode
    • checkExists()   开始检查ZNode是否存在的操作. 可以调用额外的方法(监控或者后台处理)并在最后调用forPath()指定要操作的ZNode
    • getData()       开始获得ZNode节点数据的操作. 可以调用额外的方法(监控、后台处理或者获取状态watch, background or get stat) 并在最后调用forPath()指定要操作的ZNode
    • setData()       开始设置ZNode节点数据的操作. 可以调用额外的方法(版本或者后台处理) 并在最后调用forPath()指定要操作的ZNode
    • getChildren()   开始获得ZNode的子节点列表。 以调用额外的方法(监控、后台处理或者获取状态watch, background or get stat) 并在最后调用forPath()指定要操作的ZNode
    • inTransaction() 开始是原子ZooKeeper事务. 可以复合create, setData, check, and/or delete 等操作然后调用commit()作为一个原子操作提交
    3.通知 Notifications
        服务于后台操作和监控(watch)的通知通过ClientListener接口发布。你通过CuratorFramework实例的addListener方法可以注册监听器。
    其事件触发时间说明:
    • CuratorListenable:当使用后台线程操作时,后台线程执行完成就会触发,例如:client.getData().inBackground().forPath("/test");后台获取节点数据,获取完成之后触发。
    • ConnectionStateListenable:当连接状态变化时触发。
    • UnhandledErrorListenable:当后台操作发生异常时触发。
    CuratorListenable事件触发返回的数据如下:
    事件类型 事件返回数据
    CREATE getResultCode() and getPath()
    DELETE getResultCode() and getPath()
    EXISTS getResultCode(), getPath() and getStat()
    GET_DATA getResultCode(), getPath(), getStat() and getData()
    SET_DATA getResultCode(), getPath() and getStat()
    CHILDREN getResultCode(), getPath(), getStat(), getChildren()
    SYNC getResultCode(), getStat()
    GET_ACL getResultCode(), getACLList()
    SET_ACL getResultCode()
    TRANSACTION getResultCode(), getOpResults()
    WATCHED getWatchedEvent()
    GET_CONFIG getResultCode(), getData()
    RECONFIG getResultCode(), getData()
    4.命名空间
        你可以使用命名空间Namespace避免多个应用的节点的名称冲突。 CuratorFramework提供了命名空间的概念,这样CuratorFramework会为它的API调用的path加上命名空间:
    CuratorFramework client = CuratorFrameworkFactory.builder().namespace("MyApp") ... build();
    5.临时客户端
        Curator还提供了临时的CuratorFramework:CuratorTempFramework,一定时间不活动后连接会被关闭。创建builder时不是调用build()而是调用buildTemp()。3分钟不活动连接就被关闭,你也可以指定不活动的时间。
    CuratorTempFramework client = CuratorFrameworkFactory.builder()
    .connectString("127.0.0.1:2181")// 连接串
    .retryPolicy(new RetryNTimes(10, 5000))// 重试策略
    .connectionTimeoutMs(100) // 连接超时
    .sessionTimeoutMs(100) // 会话超时
    .buildTemp(100, TimeUnit.MINUTES); // 临时客户端并设置连接时间
    它只提供了下面几个方法:
    public void close();
    public CuratorTransaction inTransaction() throws Exception;
    public TempGetDataBuilder getData() throws Exception;
    6.Retry策略
        retry策略可以改变retry的行为。 它抽象出RetryPolicy接口, 包含一个方法public boolean allowRetry(int retryCount, long elapsedTimeMs);。 在retry被尝试执行前, allowRetry()被调用,并且将当前的重试次数和操作已用时间作为参数. 如果返回true, retry被执行。否则异常被抛出。
    Curator本身提供了几个策略:
    • ExponentialBackoffRetry:重试一定次数,每次重试sleep更多的时间
    • RetryNTimes:重试N次
    • RetryOneTime:重试一次
    • RetryUntilElapsed:重试一定的时间

    4.Apache Curator Utilities

        Curator提供了一组工具类和方法用来测试基于Curator的应用。 并且提供了操作ZNode辅助类以及其它一些数据结构
    1.Test Server
        curator-test提供了TestingServer类。 这个类创建了一个本地的, 同进程的ZooKeeper服务器用来测试。
    1. public static void main(String[] args) throws Exception
    2. {
    3. TestingServer server = new TestingServer();
    4. CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), new ExponentialBackoffRetry(1000, 3));
    5. client.getConnectionStateListenable().addListener(new ConnectionStateListener()
    6. {
    7. @Override
    8. public void stateChanged(CuratorFramework client, ConnectionState newState)
    9. {
    10. System.out.println("连接状态:" + newState.name());
    11. }
    12. });
    13. client.start();
    14. System.out.println(client.getChildren().forPath("/"));
    15. client.create().forPath("/test");
    16. System.out.println(client.getChildren().forPath("/"));
    17. CloseableUtils.closeQuietly(client);
    18. CloseableUtils.closeQuietly(server);
    19. System.out.println("OK!");
    20. }
    2.Test Cluster
        curator-test提供了TestingCluster类。 这个类创建了一个内部的ZooKeeper集群用来测试。
    1. public static void main(String[] args) throws Exception
    2. {
    3. TestingCluster cluster = new TestingCluster(3);
    4. cluster.start();
    5. for (TestingZooKeeperServer server : cluster.getServers())
    6. {
    7. System.out.println(server.getInstanceSpec());
    8. }
    9. cluster.stop();
    10. CloseableUtils.closeQuietly(cluster);
    11. System.out.println("OK!");
    12. }
    3.ZKPaths
    提供了各种静态方法来操作ZNode:
    • getNodeFromPath: 从一个全路径中得到节点名, 比如 "/one/two/three" 返回 "three"
    • mkdirs: 确保所有的节点都已被创建
    • getSortedChildren: 得到一个给定路径的子节点, 按照sequence number排序
    • makePath: 给定父路径和子节点,创建一个全路径
    4.EnsurePath
        确保一个特定的路径被创建。当它第一次使用时,一个同步ZKPaths.mkdirs(ZooKeeper, String)调用被触发来确保完整的路径都已经被创建。后续的调用将不是同步操作.用法:
    1. EnsurePath ensurePath = new EnsurePath(aFullPathToEnsure);
    2. ...
    3. String nodePath = aFullPathToEnsure + "/foo";
    4. ensurePath.ensure(zk); // first time syncs and creates if needed
    5. zk.create(nodePath, ...);
    6. ...
    7. ensurePath.ensure(zk); // subsequent times are NOPs
    8. zk.create(nodePath, ...);
    注意: 此方法namespace会参与路径名字的创建。
    5.Blocking Queue Consumer(阻塞队列消费者)
        请参看Distributed Queue 和 Distributed Priority Queue。提供JDK BlockingQueue类似的行为。
    6.Queue Sharder
        由于zookeeper传输层的限制,单一的队列如果超过10K的元素会被分割(break)。这个类为多个分布式队列提供了一个facade。它监控队列,如果一个队列超过这个阈值,一个新的队列就被创建。在这些队列中Put是分布式的。
    7.Reaper and ChildReaper
    Reaper
        可以用来删除锁的父路径。定时检查路径被加入到reaper中。当检查时,如果path没有子节点/路径,此路径将被删除。每个应用中CLient应该只创建一个reaper实例。必须将lock path加到这个readper中。reaper会定时的检查删除它们。
    ChildReaper
        用来清除父节点下所有的空节点。定时的调用getChildren()并将空节点加入到内部管理的reaper中。
    注意:应该考虑使用LeaderSelector来运行Reapers,因为它们不需要在每个client运行

    5.Apache Curator Client

        Curator client使用底层的API, 强烈推荐你是用Curator Framework代替使用CuratorZookeeperClient
    1.背景
    CuratorZookeeperClient 是ZooKeeper client的包装类。但是提供了更简单方式, 而且可以减少错误的发生。它提供了下列的特性:
    • 持续的连接管理 - ZooKeeper有很多的关于连接管理的警告(你可以到ZooKeeper FAQ查看细节)。CuratorZookeeperClient 可以自动的管理这些事情。
    • retry - 提供一个方式处理retry(重试)。
    • Test ZooKeeper server - 提供一个进程内的ZooKeeper测试服务器用来测试和实验。
    2.方法
    • Constructor - 创建一个给定ZooKeeper集群的连接。 你可以传入一个可选的watcher. 必须提供Retry策略
    • getZooKeeper() - 返回管理的ZooKeeper实例. 重要提示: a) 它会花费些许时间等待连接来完成, 在使用其它方法之前你应该校验连接是否完成. b) 管理的ZooKeeper实例可以根据特定的事件而改变。 不要持有实例太长时间. 总是调用getZooKeeper()得到一个新的实例
    • isConnected() - 返回ZooKeeper client当前连接状态
    • blockUntilConnectedOrTimedOut() - block知道连接成功或者超时
    • close() - 关闭连接
    • setRetryPolicy() - 改变retry(重试)策略
    • newRetryLoop() - 分配一个新的Retry Loop(重试循环)
    3.Retry Loop(重试循环)
        由于各种各样的原因,在zookeeper集群上的操作难免遇到失败的情况。最佳实践表明应该提供重试机制。Retry Loop为此而生。每个操作都被包装在一个Retry Loop中。下面是一个典型的处理流程:
    1. RetryLoop retryLoop = client.newRetryLoop();
    2. while ( retryLoop.shouldContinue() )
    3. {
    4. try
    5. {
    6. // perform your work
    7. ...
    8. // it's important to re-get the ZK instance as there may have been an error and the instance was re-created
    9. ZooKeeper zk = client.getZookeeper();
    10. retryLoop.markComplete();
    11. }
    12. catch ( Exception e )
    13. {
    14. retryLoop.takeException(e);
    15. }
    16. }
        Retry Loop维护一定数量的retry, 它还决定一个错误是否可以要执行retry。 假如一个错误需要retry,Retry策略被调用来决定retry是要要执行,执行多少次才放弃。
        很方便地,RetryLoop 提供了一个静态方法使用Callable来执行一个完整retry loop。
    1. RetryLoop.callWithRetry(client, new Callable<Void>()
    2. {
    3. @Override
    4. public Void call() throws Exception
    5. {
    6. // do your work here - it will get retried if needed
    7. return null;
    8. }
    9. });
    4.Retry策略(重试策略)
        retry策略可以改变retry的行为。它抽象出RetryPolicy接口,包含一个方法public boolean allowRetry(int retryCount, long elapsedTimeMs)。在retry被尝试执行前,allowRetry()被调用,并且将当前的重试次数和操作已用时间作为参数.如果返回true, retry被执行。否则异常被抛出。
    Curator本身提供了几个策略(在 com.netflix.curator.retry 包下):
    • ExponentialBackoffRetry:重试一定次数,每次重试sleep更多的时间
    • RetryNTimes:重试N次
    • RetryOneTime:重试一次
    • RetryUntilElapsed:重试一定的时间
    -------------------------------------------------------------------------------------------------------------------------------



  • 相关阅读:
    CodeForces 288A Polo the Penguin and Strings (水题)
    CodeForces 289B Polo the Penguin and Matrix (数学,中位数)
    CodeForces 289A Polo the Penguin and Segments (水题)
    CodeForces 540C Ice Cave (BFS)
    网站后台模板
    雅图CAD
    mbps
    WCF学习-协议绑定
    数据库建表经验总结
    资源位置
  • 原文地址:https://www.cnblogs.com/LiZhiW/p/4926385.html
Copyright © 2020-2023  润新知