跟着实例学习ZooKeeper的用法: Curator扩展库

还记得Curator提供哪几个组件吗? 我们不妨回顾一下:

  • Recipes
  • Framework
  • Utilities
  • Client
  • Errors
  • Extensions

前面的例子其实前五个组件都涉及到了, 比如Utilities例子的TestServer, Client里的CuratorZookeeperClient, Errors里的ConnectionStateListener等。 还有最后一个组件我们还没有介绍,那就是Curator扩展组件。

Recipes组件包含了丰富的Curator应用的组件。 但是这些并不是ZooKeeper Recipe的全部。 大量的分布式应用已经抽象出了许许多多的的Recipe,其中有些还是可以通过Curator来实现。 如果不断都将这些Recipe都增加到Recipes中, Recipes会变得越来越大。 为了避免这种状况, Curator把一些其它的Recipe放在单独的包中, 命名方式就是curator-x-<name>,比如curator-x-discovery, curator-x-rpc。 本文就是介绍curator-x-discovery。

这是一个服务发现的Recipe。
我们在介绍临时节点Ephemeral Node的时候就讲到, 可以通过临时节点创建一个服务注册机制。 服务启动后创建临时节点, 服务断掉后临时节点就不存在了。 这个扩展抽象了这种功能,听过了一套API,可以实现服务发现机制。

服务类

我们先介绍一下例子中的服务类。InstanceDetails定义了服务实例的基本信息,实际中可能会定义更详细的信息。

package com.colobu.zkrecipe.discovery; import org.codehaus.jackson.map.annotate.JsonRootName; /**
 * In a real application, the Service payload will most likely be more detailed
 * than this. But, this gives a good example.
 */ @JsonRootName("details") public class InstanceDetails { private String description; public InstanceDetails() { this("");
    } public InstanceDetails(String description) { this.description = description;
    } public void setDescription(String description) { this.description = description;
    } public String getDescription() { return description;
    }
}

ExampleServer相当与你在分布式环境中的服务应用。 每个服务应用实例都类似这个类, 应用启动时调用start, 关闭时调用close。

package com.colobu.zkrecipe.discovery; import java.io.Closeable; import java.io.IOException; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.utils.CloseableUtils; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.apache.curator.x.discovery.UriSpec; import org.apache.curator.x.discovery.details.JsonInstanceSerializer; /**
 * This shows a very simplified method of registering an instance with the
 * service discovery. Each individual instance in your distributed set of
 * applications would create an instance of something similar to ExampleServer,
 * start it when the application comes up and close it when the application
 * shuts down.
 */ public class ExampleServer implements Closeable { private final ServiceDiscovery<InstanceDetails> serviceDiscovery; private final ServiceInstance<InstanceDetails> thisInstance; public ExampleServer(CuratorFramework client, String path, String serviceName, String description) throws Exception { // in a real application, you‘d have a convention of some kind for the // URI layout UriSpec uriSpec = new UriSpec("{scheme}://foo.com:{port}");
        thisInstance = ServiceInstance.<InstanceDetails> builder().name(serviceName).payload(new InstanceDetails(description))
                .port((int) (65535 * Math.random())) // in a real application, // you‘d use a common // port .uriSpec(uriSpec).build(); // if you mark your payload class with @JsonRootName the provided // JsonInstanceSerializer will work JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(InstanceDetails.class);
        serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class).client(client).basePath(path).serializer(serializer)
                .thisInstance(thisInstance).build();
    } public ServiceInstance<InstanceDetails> getThisInstance() { return thisInstance;
    } public void start() throws Exception {
        serviceDiscovery.start();
    } @Override public void close() throws IOException {
        CloseableUtils.closeQuietly(serviceDiscovery);
    }
}

发现中心

DiscoveryExample提供了增加,删除,显示,注册已有的服务的功能。 注意此处服务注册是由ExampleServer自己完成的, 这比较符合实际的情况。 实际情况是服务自己起来后主动注册服务。 但是此处启动又是由DiscoveryExample来调用, 纯粹为了演示使用。 你可以根据你自己的情况合理安排服务的注册和启动。

random命令提供了一个完全由DiscoveryExample控制的服务。 它负责注册一个服务并启动。

调用close就关闭了服务。

package com.colobu.zkrecipe.discovery; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingServer; import org.apache.curator.utils.CloseableUtils; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.apache.curator.x.discovery.ServiceProvider; import org.apache.curator.x.discovery.details.JsonInstanceSerializer; import org.apache.curator.x.discovery.strategies.RandomStrategy; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; public class DiscoveryExample { private static final String PATH = "/discovery/example"; public static void main(String[] args) throws Exception { // This method is scaffolding to get the example up and running TestingServer server = new TestingServer();
        CuratorFramework client = null;
        ServiceDiscovery<InstanceDetails> serviceDiscovery = null;
        Map<String, ServiceProvider<InstanceDetails>> providers = Maps.newHashMap(); try {
            client = CuratorFrameworkFactory.newClient(server.getConnectString(), new ExponentialBackoffRetry(1000, 3));
            client.start();
            JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(InstanceDetails.class);
            serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class).client(client).basePath(PATH).serializer(serializer).build();
            serviceDiscovery.start();
            processCommands(serviceDiscovery, providers, client);
        } finally { for (ServiceProvider<InstanceDetails> cache : providers.values()) {
                CloseableUtils.closeQuietly(cache);
            }
            CloseableUtils.closeQuietly(serviceDiscovery);
            CloseableUtils.closeQuietly(client);
            CloseableUtils.closeQuietly(server);
        }
    } private static void processCommands(ServiceDiscovery<InstanceDetails> serviceDiscovery, Map<String, ServiceProvider<InstanceDetails>> providers, CuratorFramework client) throws Exception { // More scaffolding that does a simple command line processor printHelp();
        List<ExampleServer> servers = Lists.newArrayList(); try {
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); boolean done = false; while (!done) {
                System.out.print("> ");
                String line = in.readLine(); if (line == null) { break;
                }
                String command = line.trim();
                String[] parts = command.split("\\s"); if (parts.length == 0) { continue;
                }
                String operation = parts[0];
                String args[] = Arrays.copyOfRange(parts, 1, parts.length); if (operation.equalsIgnoreCase("help") || operation.equalsIgnoreCase("?")) {
                    printHelp();
                } else if (operation.equalsIgnoreCase("q") || operation.equalsIgnoreCase("quit")) {
                    done = true;
                } else if (operation.equals("add")) {
                    addInstance(args, client, command, servers);
                } else if (operation.equals("delete")) {
                    deleteInstance(args, command, servers);
                } else if (operation.equals("random")) {
                    listRandomInstance(args, serviceDiscovery, providers, command);
                } else if (operation.equals("list")) {
                    listInstances(serviceDiscovery);
                }
            }
        } finally { for (ExampleServer server : servers) {
                CloseableUtils.closeQuietly(server);
            }
        }
    } private static void listRandomInstance(String[] args, ServiceDiscovery<InstanceDetails> serviceDiscovery, Map<String, ServiceProvider<InstanceDetails>> providers, String command) throws Exception { // this shows how to use a ServiceProvider // in a real application you‘d create the ServiceProvider early for the // service(s) you‘re interested in if (args.length != 1) {
            System.err.println("syntax error (expected random <name>): " + command); return;
        }
        String serviceName = args[0];
        ServiceProvider<InstanceDetails> provider = providers.get(serviceName); if (provider == null) {
            provider = serviceDiscovery.serviceProviderBuilder().serviceName(serviceName).providerStrategy(new RandomStrategy<InstanceDetails>()).build();
            providers.put(serviceName, provider);
            provider.start();
            Thread.sleep(2500); // give the provider time to warm up - in a real // application you wouldn‘t need to do this }
        ServiceInstance<InstanceDetails> instance = provider.getInstance(); if (instance == null) {
            System.err.println("No instances named: " + serviceName);
        } else {
            outputInstance(instance);
        }
    } private static void listInstances(ServiceDiscovery<InstanceDetails> serviceDiscovery) throws Exception { // This shows how to query all the instances in service discovery try {
            Collection<String> serviceNames = serviceDiscovery.queryForNames();
            System.out.println(serviceNames.size() + " type(s)"); for (String serviceName : serviceNames) {
                Collection<ServiceInstance<InstanceDetails>> instances = serviceDiscovery.queryForInstances(serviceName);
                System.out.println(serviceName); for (ServiceInstance<InstanceDetails> instance : instances) {
                    outputInstance(instance);
                }
            }
        } finally {
            CloseableUtils.closeQuietly(serviceDiscovery);
        }
    } private static void outputInstance(ServiceInstance<InstanceDetails> instance) {
        System.out.println("\t" + instance.getPayload().getDescription() + ": " + instance.buildUriSpec());
    } private static void deleteInstance(String[] args, String command, List<ExampleServer> servers) { // simulate a random instance going down // in a real application, this would occur due to normal operation, a // crash, maintenance, etc. if (args.length != 1) {
            System.err.println("syntax error (expected delete <name>): " + command); return;
        } final String serviceName = args[0];
        ExampleServer server = Iterables.find(servers, new Predicate<ExampleServer>() { @Override public boolean apply(ExampleServer server) { return server.getThisInstance().getName().endsWith(serviceName);
            }
        }, null); if (server == null) {
            System.err.println("No servers found named: " + serviceName); return;
        }
        servers.remove(server);
        CloseableUtils.closeQuietly(server);
        System.out.println("Removed a random instance of: " + serviceName);
    } private static void addInstance(String[] args, CuratorFramework client, String command, List<ExampleServer> servers) throws Exception { // simulate a new instance coming up // in a real application, this would be a separate process if (args.length < 2) {
            System.err.println("syntax error (expected add <name> <description>): " + command); return;
        }
        StringBuilder description = new StringBuilder(); for (int i = 1; i < args.length; ++i) { if (i > 1) {
                description.append(‘ ‘);
            }
            description.append(args[i]);
        }
        String serviceName = args[0];
        ExampleServer server = new ExampleServer(client, PATH, serviceName, description.toString());
        servers.add(server);
        server.start();
        System.out.println(serviceName + " added");
    } private static void printHelp() {
        System.out.println("An example of using the ServiceDiscovery APIs. This example is driven by entering commands at the prompt:\n");
        System.out.println("add <name> <description>: Adds a mock service with the given name and description");
        System.out.println("delete <name>: Deletes one of the mock services with the given name");
        System.out.println("list: Lists all the currently registered services");
        System.out.println("random <name>: Lists a random instance of the service with the given name");
        System.out.println("quit: Quit the example");
        System.out.println();
    }
}

其它扩展

其它两个扩展Curator RPC Proxy(curator-x-rpc)扩展和Service Discovery Server(curator-x-discovery-server)是为了桥接非Java应用的扩展,本系列将不再介绍了。感兴趣的朋友可以看下面的 文档。 Curator Service Discovery Curator RPC Proxy

时间: 2024-10-13 06:32:03

跟着实例学习ZooKeeper的用法: Curator扩展库的相关文章

[转载] 跟着实例学习zookeeper 的用法

原文: http://ifeve.com/zookeeper-curato-framework/ zookeeper 的原生客户端库过于底层, 用户为了使用 zookeeper需要编写大量的代码, 为此Curator框架对 zookeeper 进行了高层次的语义封装, 简化使用 zookeeper 的成本. 只可惜 curator 框架仅仅支持 java 语言, 期待 c++版本出现(或者我们自己尝试实现一个) 跟着实例学习ZooKeeper的用法: Curator框架应用 前面的几篇文章介绍了

跟着实例学习ZooKeeper的用法: Leader选举

http://colobu.com/2014/12/12/zookeeper-recipes-by-example-1/ ZooKeeper官方给出了使用zookeeper的几种用途. Leader Election Barriers Queues Locks Two-phased Commit 其它应用如Name Service, Configuration, Group Membership 在实际使用ZooKeeper开发中,我们最常用的是Apache Curator. 它由Netflix

12.Curator扩展库

Recipes组件包含了丰富的Curator应用的组件.但是这些并不是ZooKeeper Recipe的全部.大量的分布式应用已经抽象出了许许多多的的Recipe,其中有些还是可以通过Curator来实现. 如果不断都将这些Recipe都增加到Recipes中,Recipes会变得越来越大.为了避免这种状况,Curator把一些其它的Recipe放在单独的包中,命名方式就是curator-x-,比如curator-x-discovery, curator-x-rpc.本文就是主要介绍curato

用 phpize 编译共享 PECL 扩展库

有时候不能用 pecl 安装命令.这可能是因为在防火墙后面,或者是因为想要安装的扩展库还没有 PECL 兼容的包,例如 SVN 中尚未发布的扩展库.如果要编译这种扩展库,可以用更底层的编译工具来手工进行编译. phpize 命令是用来准备 PHP 扩展库的编译环境的.下面例子中,扩展库的源程序位于 extname 目录中: $ cd extname $ phpize $ ./configure $ make # make install 成功的安装将创建 extname.so 并放置于 PHP

ThinkPHP5 支付宝支付扩展库(超简单,超好用~)

我的想法是,只需要调用一个静态方法就可以完成所需要的所有工作,再也不必重复造轮子! ThinkPHP5 支付宝支付扩展库, 包括手机网站支付.电脑网站支付.支付查询.退款.退款查询.对账单等 随着支付宝官方不断更新(目前是2017年7月21日),大家可以在GitHub查看说明说明 https://github.com/dream2023/ThinkPHP5-alipay 用法 电脑网站支付 Pagepay.php 调用 \alipay\Pagepay::pay($params) 即可 手机网站支

关于lua扩展库lpack的使用指南

最近在研究luasocket,准备用全部用lua的扩展库来实现一套轻量级框架,用来做一些工具.简单的游戏服务器,以及作为网络库用在cocos2dx中. 完善的网络库必然会遇到粘包.半包的问题,luasocket也不例外,由于网络部分在lua,协议的制定和buff的解析都没有合适的方案,又不想在C++中来封装接口,后面在网上查了一些资料,发现lua也有一个二进制打包的扩展库--lpack,了解之后发现还是蛮好用的,就决定使用它来做buff解析,用以解决粘包.半包的问题. 首先需要下载lpack的源

ThinkPHP5 支付宝 电脑与手机支付扩展库

ThinkPHP5 电脑与手机支付扩展库(2017年9月18日) 使用说明 在默认配置情况下,将文件夹拷贝到根目录即可, 其中extend目录为支付扩展目录, application\extra\alipay.php为配置文件 需要在配置文件application\extra\alipay.php中填写必要的参数 注意 错误采用抛出异常的方式, 可根据自己的业务在统一接口进行修改 用法 电脑网站支付 Pagepay.php 调用 \alipay\Pagepay::pay($params) 即可

Github上比较流行的PHP扩展库项目

这里列出比较常用的PHP开源扩展库项目: swoole, C扩展实现的PHP异步并行网络通信框架,可以重新定义PHP.过去PHP只能做Web项目,现在有了Swoole.任意服务器端程序都可以用PHP来写. yaf,C扩展实现的高性能Web开发框架. php-webim,基于swoole实现的Web即时聊天工具,支持websocket+http comet长链接推送,可以发送文字内容和图片. react 使用PHP代码实现异步框架.如果说swoole是node.js的升级版,react.php就是

Centos中编辑php扩展库

今天需要在Centos中编译Exif库以便获取图片的exif信息,可在Linux中从来没有编译过扩展库呀,只好查资料了.发现是用phpize这个东东来编译扩展. 首先执行了下 php -i | grep config 看了下编译php的时候没有加上exif扩展. 那么第一步,当然是进入源码目录里面的Exif目录下面.然后再找到phpize的路径,phpize这个一般是安装完php后的目录下面的 cd /alidata/server/php-5.4/ext/exif /alidata/server