• Apache Curator异步API和事务API


    原生API中基本上所有的操作都有提供异步操作,Curator也有提供异步操作的API。

    异步操作
    在使用以上针对节点的操作API时,我们会发现每个接口都有一个inBackground()方法可供调用。此接口就是Curator提供的异步调用入口。对应的异步处理接口为BackgroundCallback。此接口指提供了一个processResult的方法,用来处理回调结果。其中processResult的参数event中的getType()包含了各种事件类型,getResultCode()包含了各种响应码。

    /**
    * Called when the async background operation completes
    *
    * @param client the client
    * @param event operation result details
    * @throws Exception errors
    */
    public void processResult(CuratorFramework client, CuratorEvent event) throws Exception;

    事件类型

    getType(),代表本次事件的类型,主要有

    CREATE、DELETE、EXISTS、GET_DATA、SET_DATA、CHILDREN、SYNC、GET_ACL、WATCHED和CLOSING 。

    分别代表

    curatorFramework.create()、
    curatorFramework.delete()、
    curatorFramework.checkExists()、
    curatorFramework.getData()、
    curatorFramework.setData()、
    curatorFramework.getChildren()、
    curatorFramework.sync()、
    curatorFramework.getACL()、
    usingWatcher()、
    watched()。

    响应码
    响应码用于标识事件的结果状态,所有响应码都被定义在
    org.apache.zookeeper.KeeperException.Code类中,比较常见的响应码有OK(0),CONNECTIONLOSS (-4),NODEEXISTS (-110),SESSIONEXPIRED (-112),分别代表调用成功,客户端与服务端连接已断开,指定节点已存在,会话已超时,还有很多错误码可以查阅Code类中的代码。

    inBackground的方法参数列表:

    public T inBackground();
    public T inBackground(Object context);
    public T inBackground(BackgroundCallback callback);
    public T inBackground(BackgroundCallback callback, Object context);
    public T inBackground(BackgroundCallback callback, Executor executor);
    public T inBackground(BackgroundCallback callback, Object context, Executor executor);

    context参数:传给服务端的参数,会在异步通知中传回来

    executor参数:此接口还允许传入一个Executor实例,用一个专门线程池来处理返回结果之后的业务逻辑。

    异步创建节点的例子,其他节点类似:

    public static void main(String[] args) throws Exception {
    
        String connectionString = "192.168.58.42:2181";
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3,Integer.MAX_VALUE);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
        curatorFramework.start();
    
        //=========================创建节点=============================
    
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        curatorFramework.create()
                .creatingParentsIfNeeded()//递归创建,如果没有父节点,自动创建父节点
                .withMode(CreateMode.PERSISTENT)//节点类型,持久节点
                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)//设置ACL,和原生API相同
                .inBackground(new BackgroundCallback() {
                    @Override
                    public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                        System.out.println("===>响应码:" + event.getResultCode()+",type:" + event.getType());
                        System.out.println("===>Thread of processResult:"+Thread.currentThread().getName());
                        System.out.println("===>context参数回传:" + event.getContext());
                    }
                },"传给服务端的内容,异步会传回来", executorService)
                .forPath("/node10","123456".getBytes());
        Thread.sleep(3000);
    
    
        curatorFramework.create()
                .creatingParentsIfNeeded()//递归创建,如果没有父节点,自动创建父节点
                .withMode(CreateMode.PERSISTENT)//节点类型,持久节点
                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)//设置ACL,和原生API相同
                .inBackground(new BackgroundCallback() {
                    @Override
                    public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                        System.out.println("===>响应码:" + event.getResultCode()+",type:" + event.getType());
                        System.out.println("===>Thread of processResult:"+Thread.currentThread().getName());
                        System.out.println("===>context参数回传:" + event.getContext());
                    }
                },"传给服务端的内容,异步会传回来")
                .forPath("/node10","123456".getBytes());
        Thread.sleep(3000);
        executorService.shutdown();
    }

    运行程序,输出结果如下:

    ===>响应码:0,type:CREATE
    ===>Thread of processResult:pool-3-thread-1
    ===>context参数回传:传给服务端的内容,异步会传回来
    ===>响应码:-110,type:CREATE
    ===>Thread of processResult:main-EventThread
    ===>context参数回传:传给服务端的内容,异步会传回来

    上面这个程序使用了异步接口inBackground来创建节点,前后两次调用,创建的节点名相同。从两次返回的event可以看出,第一次返回的响应码是0,表明此次次调用成功,即创建节点成功;而第二次返回的响应码是-110,表明该节点已经存在,无法重复创建。这些响应码和ZooKeeper原生的响应码是一致的。

    注意:如果自己指定了线程池,那么相应的操作就会在线程池中执行,如果没有指定,那么就会使用Zookeeper的EventThread线程对事件进行串行处理.在ZooKeeeper中,所有的异步通知事件都是由EventThread这个线程来处理的——EventThread线程用于穿行处理所有的事件通知。EventThread的“串行处理机制”在绝大部分应用场景下能够保证对事件处理的顺序性,但这个特性也有其弊端,就是一旦碰上一个复杂的处理单元,就会消耗过多的处理时间,从而影响对其他事件得分处理。因此,在上面的inBacigorund接口中,允许用户传入一个Executor实例,这样一来,就可以把那些复杂的事件处理放到一个专门的线程池中去。

    事务操作
    此外,Curator还支持事务,一组crud操作同生同灭。代码如下:

    public class TransactionExamples {
    
        public static void main(String[] args) throws Exception {
            String connectionString = "192.168.58.42:2181";
            ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3,Integer.MAX_VALUE);
            CuratorFramework client = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
            client.start();
    
            //开始事务操作
            CuratorOp createParentNode = client.transactionOp().create().forPath("/a", "some data".getBytes());
            CuratorOp createChildNode = client.transactionOp().create().forPath("/a/path", "other data".getBytes());
            CuratorOp setParentNode = client.transactionOp().setData().forPath("/a", "other data".getBytes());
            CuratorOp deleteParent = client.transactionOp().delete().forPath("/a");
    
            Collection<CuratorTransactionResult>    results = client.transaction().forOperations(createParentNode, createChildNode, setParentNode,deleteParent);
    
            for ( CuratorTransactionResult result : results ){
                System.out.println(result.getForPath() + " - " + result.getType());
            }
        }
    }

    上面的例子最后会抛异常,由于最后一步delete的节点不存在,所以整个事务commit失败。

    注意:事务操作的时候不支持自动创建父节点,也就是说你想创建的节点如果是多层的,那么父节点一定要存在才可以。

    欢迎关注微信公众号:大数据从业者
  • 相关阅读:
    通信的真正端点不是主机而是主机中的进程
    futures
    What's the customers care is only Myinput and Uroutput on the Cloud.What's more,MySecurity.
    r
    迭代器遍历列表 构造方法 constructor ArrayList Vector LinkedList Array List 时间复杂度
    2009年4月,Twitter宣布他们已经把大部分后端程序从Ruby迁移到Scala
    So the type system doesn’t feel so static.

    Unit redis-server.service is masked.
    Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令 PHONY伪目标实践
  • 原文地址:https://www.cnblogs.com/felixzh/p/15681967.html
Copyright © 2020-2023  润新知