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

1.curator-x-discovery介绍

    curator-x-discovery是一个服务发现的解决方案。我们在介绍临时节点Ephemeral Node的时候就讲到,可以通过临时节点创建一个服务注册机制。服务启动后创建临时节点,服务断掉后临时节点就不存在了。这个扩展抽象了这种功能,通过一套API,可以实现服务发现机制。具体示例参考官网:http://curator.apache.org/curator-x-discovery/index.html
1.ServiceInstance类
    ServiceInstance是一个服务实例所代表的类。ServiceInstances有名称、id、地址、端口和/或ssl端口,和一个可选的payload属性(用户定义的)。 ServiceInstances序列化并存储在Zookeeper中的方式如下:
  1. base path
  2. |_______ service A name
  3. |__________ instance 1 id --> (serialized ServiceInstance)
  4. |__________ instance 2 id --> (serialized ServiceInstance)
  5. |__________ ...
  6. |_______ service B name
  7. |__________ instance 1 id --> (serialized ServiceInstance)
  8. |__________ instance 2 id --> (serialized ServiceInstance)
  9. |__________ ...
  10. |_______ ...
    ServiceInstances类的成员如下图:

2.ServiceProvider类
    ServiceProvider是主要的抽象类。它封装了发现服务为特定的命名服务和提供者策略。提供者策略方案选择一个实例从一组给定的服务实例。有三个捆绑策略:轮询调度、随机和粘性(总是选择相同的一个)。
    serviceprovider分配使用ServiceProviderBuilder。你获得一个ServiceProviderBuilder ServiceDiscovery(见下文)。 ServiceProviderBuilder允许您设置服务名称和其他几个可选值。
    ServiceProvider开始必须调用start()方法。当使用完成应该调用close()方法。ServiceProvider接口有以下两个重要的方法: 
  1. /**
  2. * Return an instance for a single use. <b>IMPORTANT: </b> users
  3. * should not hold on to the instance returned. They should always get a fresh instance.
  4. *
  5. * @return the instance to use
  6. * @throws Exception any errors
  7. */
  8. public ServiceInstance<T> getInstance() throws Exception;
  9. /**
  10. * Return the current available set of instances <b>IMPORTANT: </b> users
  11. * should not hold on to the instance returned. They should always get a fresh list.
  12. *
  13. * @return all known instances
  14. * @throws Exception any errors
  15. */
  16. public Collection<ServiceInstance<T>> getAllInstances() throws Exception;
getInstance()方法用于获取服务实例。getAllInstances()方法获取所有的服务实例。以下是ServiceProvider接口的所有成员。

3.ServiceDiscovery类
    为了创建ServiceProvider,你必须有一个ServiceDiscovery。它是由一个ServiceDiscoveryBuilder创建。开始必须调用start()方法。当使用完成应该调用close()方法。
 
实例的稳定性:如果一个特定的实例有一个错误(如:I/O错误),你应该调用ServiceProvider.noteError()。该ServiceProvider将暂时认为有错误的情况下,确定为“down”的实例。The thresholds and timeouts for down instances are set via the DownInstancePolicy which can be passed to ServiceProviderBuilder (note: a default DownInstancePolicy is used if you don't specify one).

2.低级别的API介绍

    ServiceProvider API都是你应该给最需要的目的。然而,对于更细粒度的控制,您可以使用这些方法: 
1.服务注册/取消注册
    通常,您将您的应用程序的服务描述符传递给ServiceDiscovery构造函数,它会自动注册/注销。不过,如果您需要手动做这个,使用这些方法:
  1. /**
  2. * Register/re-register a service 注册服务
  3. *
  4. * @param service service to add
  5. * @throws Exception errors
  6. */
  7. public void registerService(ServiceInstance<T> service) throws Exception;
  8. /**
  9. * Unregister/remove a service instance 取消注册服务
  10. *
  11. * @param service the service
  12. * @throws Exception errors
  13. */
  14. public void unregisterService(ServiceInstance<T> service) throws Exception;
2.查询服务
    您可以查询服务名称,特定服务的所有实例,或单一的服务实例。 
  1. /**
  2. * Return the names of all known services
  3. *
  4. * @return list of service names
  5. * @throws Exception errors
  6. */
  7. public Collection<String> queryForNames() throws Exception;
  8. /**
  9. * Return all known instances for the given service
  10. *
  11. * @param name name of the service
  12. * @return list of instances (or an empty list)
  13. * @throws Exception errors
  14. */
  15. public Collection<ServiceInstance<T>> queryForInstances(String name) throws Exception;
  16. /**
  17. * Return a service instance POJO
  18. *
  19. * @param name name of the service
  20. * @param id ID of the instance
  21. * @return the instance or <code>null</code> if not found
  22. * @throws Exception errors
  23. */
  24. public ServiceInstance<T> queryForInstance(String name, String id) throws Exception;
3.服务缓存
    上面的查询方法直接调用Zookeeper。 如果你需要经常查询的服务可以使用ServiceCache。它在内存中缓存实例的列表为特定的服务。它使用一个观察者保持最新的列表。
    你创建一个ServiceCache通过调用ServiceDiscovery.serviceCacheBuilder()方法。ServiceCache对象开始必须调用start()方法。当使用完成应该调用close()方法。你可以得到当前已知的实例列表服务通过调用:
  1. /**
  2. * Return the current list of instances. NOTE: there is no guarantee of freshness. This is
  3. * merely the last known list of instances. However, the list is updated via a ZooKeeper watcher
  4. * so it should be fresh within a window of a second or two.
  5. *
  6. * @return the list
  7. */
  8. public List<ServiceInstance<T>> getInstances();
    ServiceCache支持得到通知的侦听器,当观察者更新实例的列表(需要增加监听ServiceCacheListener):
  1. /**
  2. * Listener for changes to a service cache
  3. */
  4. public interface ServiceCacheListener extends ConnectionStateListener
  5. {
  6. /**
  7. * Called when the cache has changed (instances added/deleted, etc.)
  8. */
  9. public void cacheChanged();
  10. }

3.curator-x-discovery使用实例

1.定义服务基本信息的类
InstanceDetails定义了服务实例的基本信息,实际中可能会定义更详细的信息。代码如下:
  1. @JsonRootName("details")
  2. public class InstanceDetails
  3. {
  4. /** 服务说明信息 */
  5. private String description;

  6. public InstanceDetails(String description)
  7. {
  8. this.description = description;
  9. }
  10. public void setDescription(String description)
  11. {
  12. this.description = description;
  13. }
  14. public String getDescription()
  15. {
  16. return description;
  17. }
  18. @Override
  19. public String toString()
  20. {
  21. return "InstanceDetails [description=" + description + "]";
  22. }
  23. }
2.服务类
ExampleServer相当与你在分布式环境中的服务应用。每个服务应用实例都类似这个类 应用启动时调用start,关闭时调用close。代码如下:
  1. public class ExampleServer implements Closeable
  2. {
  3. private final ServiceDiscovery<InstanceDetails> serviceDiscovery;//发现服务的实例类
  4. private final ServiceInstance<InstanceDetails> thisInstance;//服务注册信息实例
  5. public ExampleServer(CuratorFramework client, String path, String serviceName, String description) throws Exception
  6. {
  7. UriSpec uriSpec = new UriSpec("{scheme}://foo.com:{port}");
  8. thisInstance = ServiceInstance.<InstanceDetails>builder()
  9. .name(serviceName)
  10. .payload(new InstanceDetails(description))
  11. .port(12345)
  12. .uriSpec(uriSpec)
  13. .build();
  14. JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(InstanceDetails.class);
  15. serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class)
  16. .client(client)
  17. .basePath(path)
  18. .serializer(serializer)
  19. .thisInstance(thisInstance)
  20. .build();
  21. }
  22. public ServiceInstance<InstanceDetails> getThisInstance()
  23. {
  24. return thisInstance;
  25. }
  26. public void start() throws Exception
  27. {
  28. serviceDiscovery.start();
  29. }
  30. @Override
  31. public void close() throws IOException
  32. {
  33. CloseableUtils.closeQuietly(serviceDiscovery);
  34. }
  35. }
注意:这里的服务类并未提供任何的服务,但是在实际应用中此服务类可以有若干服务方法,用来提供服务。而且提供的服务的信息(如:说明或服务地址)应与InstanceDetails类相关联。
3.发现中心
DiscoveryExample提供了启动服务、关闭服务、遍历所有服务实例的演示。
  1. public class DiscoveryExample
  2. {
  3. public static void main(String[] args) throws Exception
  4. {
  5. String basePath = "/discoverys";
  6. BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  7. CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new RetryNTimes(10, 5000));
  8. client.start();
  9. ExampleServer exampleServer = new ExampleServer(client, basePath, "serviceName01", "服务说明");
  10. exampleServer.start();
  11. getAllService();
  12. System.out.println("服务已启动!输入回车关闭服务:");
  13. in.readLine();
  14. exampleServer.close();
  15. getAllService();
  16. System.out.println("服务已关闭!输入回车关闭连接:");
  17. in.readLine();
  18. client.close();
  19. System.out.println("连接已关闭!");
  20. System.out.println("OK!");
  21. }
  22. //遍历所有服务实例
  23. private static void getAllService() throws Exception
  24. {
  25. CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new RetryNTimes(10, 5000));
  26. client.start();
  27. JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(InstanceDetails.class);
  28. ServiceDiscovery<InstanceDetails> serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class)
  29. .client(client)
  30. .basePath("/discoverys")
  31. .serializer(serializer)
  32. .build();
  33. serviceDiscovery.start();
  34. Collection<String> serviceNames = serviceDiscovery.queryForNames();// 获取所有的服务名称
  35. for(String serviceName : serviceNames)
  36. {
  37. // 获取所有相同服务名称的所有服务实例
  38. Collection<ServiceInstance<InstanceDetails>> instances = serviceDiscovery.queryForInstances(serviceName);
  39. System.out.println(serviceName);
  40. for (ServiceInstance<InstanceDetails> instance : instances)
  41. {
  42. System.out.println("\t" + instance);
  43. }
  44. }
  45. serviceDiscovery.close();
  46. client.close();
  47. }
  48. }
注意:此处服务注册是由ExampleServer自己完成的,这比较符合实际的情况。实际情况是服务自己起来后主动注册服务。但是此处启动又是由DiscoveryExample来调用,纯粹为了演示使用。你可以根据你自己的情况合理安排服务的注册和启动。
4.测试结果及其分析
    当运行多个DiscoveryExample时,会看到如下控制台信息:
  1. serviceName01
  2. ServiceInstance{name='serviceName01', id='bb766181-4e7a-423a-974a-8ac840a9ea08', address='192.168.4.232', port=12345, sslPort=null, payload=InstanceDetails [description=服务说明], ...}
  3. ServiceInstance{name='serviceName01', id='298c5dc6-c431-41cb-8e74-6abbefecd2ee', address='192.168.4.232', port=12345, sslPort=null, payload=InstanceDetails [description=服务说明], ...}
  4. 服务已启动!输入回车关闭服务:
  5. serviceName01
  6. ServiceInstance{name='serviceName01', id='298c5dc6-c431-41cb-8e74-6abbefecd2ee', address='192.168.4.232', port=12345, sslPort=null, payload=InstanceDetails [description=服务说明], ...}
  7. 服务已关闭!输入回车关闭连接:
  8. 连接已关闭!
  9. OK!
    启动一个ExampleServer服务实例,此服务实例可以提供某些服务,ExampleServer会自动到Zookeeper上注册自己的服务信息(由InstanceDetails类提供相关信息数据),当服务关闭或服务的Zookeeper连接断开时(可能因为服务已经挂了或网络故障等原因),ExampleServer会自动删除Zookeeper上注册的服务信息。服务注册信息的数据结构如下:
  1. base path
  2. |_______ service A name
  3. |__________ instance 1 id --> (serialized ServiceInstance)
  4. |__________ instance 2 id --> (serialized ServiceInstance)
  5. |__________ ...
  6. |_______ service B name
  7. |__________ instance 1 id --> (serialized ServiceInstance)
  8. |__________ instance 2 id --> (serialized ServiceInstance)
  9. |__________ ...
  10. |_______ ...
    实际上,这就是一种服务注册信息到真实服务的映射,任何可以连接到此Zookeeper的客户端都可以看到这个服务注册信息,用来找到服务或监控服务。

4.其他扩展介绍

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

-------------------------------------------------------------------------------------------------------------------------------

11.Curator扩展库的更多相关文章

  1. PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)

    1.和mysql扩展库的区别: (1   安全性.稳定性更高 (2  提供了面向对象和面向过程两种风格 2.php.ini  中的  extension=php_mysqli.dll 解除封印 3.面 ...

  2. PHP基础Mysql扩展库

    mysql扩展库操作步骤如下: 1.连接数据库 2.选择数据库 3.设置操作编码 4.发送指令sql,并返回结果集     ddl:数据定义语句     dml:数据操作语句     dql:数据查询 ...

  3. centos下不重装php——给PHP添加新扩展库

    装完php.发现需要一些新扩展库比如常见的mysqli之类的.在不重装php安装新扩展,以一个不常用的库xsl为例. 环境:centos6.8,php5.3.29 ,osx10.11.6 我的php相 ...

  4. php mysqli扩展库之预处理操作

    分享下php使用mysqli扩展库进行预处理操作的二个例子,有意研究mysqli用法的朋友,可以参考学习下,一定会有所帮助的. 例1.使用mysqli扩展库的预处理技术 mysqli stmt 向数据 ...

  5. 树莓派安装opencv3及其扩展库

    https://www.cnblogs.com/Pyrokine/p/8921285.html 目标编译针对python的opencv以及扩展库 环境树莓派4和3B+都可以python3.7.3 py ...

  6. Layman 使用ffmpeg-php扩展库实现视频截图(默认图)

    这几天做项目,其中一个需求是用户上传视频文件到服务器,然后服务器自动截取该视频的一帧作为该视频对应的缩略图,服务器端语言采用php编写,找了半天资料,发现ffmpeg-php可以满足该需求,所以下面简 ...

  7. PHP的SPL扩展库(一)数据结构

    SPL 库也叫做 PHP 标准库,主要就是用于解决典型问题的一组接口或类的集合.这些典型问题包括什么呢?比如我们今天要讲的数据结构,还有一些设计模式的实现,就像我们之前讲过的观察者模式相关的接口在 S ...

  8. Z.ExtensionMethods 一个强大的开源扩展库

    今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去看了一下,也都只是提到而已,没有专门介绍,才引起我写这篇文档 ...

  9. PHP使用mysqli扩展库实现增删改查(面向对象版)

    mysqli扩展库是mysql扩展库的改进版本,在mysql扩展库的基础上提高了稳定性和效率,mysqli扩展库有两套东西,一套就是面向过程的mysqli另一套是面向对象的mysqli.操作方式大体和 ...

随机推荐

  1. nginx Beginner’s Guide

    这个引导给nginx做了一个基本的介绍,并描述了nginx可以做的一些基本事情. 假设nginx已经安装在了读者的电脑上,如果没有请查看官网安装页. 这个引导描述了怎么去开始和结束nginx,从新加载 ...

  2. atitit.Oracle 9 10 11 12新特性attilax总结

    atitit.Oracle 9  10 11  12新特性 1. ORACLE 11G新特性 1 1.1. oracle11G新特性 1 1.2. 审计 1 1.3. 1.   审计简介 1 1.4. ...

  3. 用React Native编写跨平台APP

    用React Native编写跨平台APP React Native 是一个编写iOS与Android平台实时.原生组件渲染的应用程序的框架.它基于React,Facebook的JavaScript的 ...

  4. redis储存中文,客服端读取出现乱码

    [root@cache03 ~]# redis-cli -h 192.168.1.112 -p 6379 192.168.1.112:6379> set chen 陈林 OK 192.168.1 ...

  5. Java类的实例化的初始化过程

    A a = new A(); new 创建对象过程: 1.类加载     代码验证 2.给对象在内存(堆)中分配空间(给属性赋值): 3.属性赋默认值: byte,short.int,long -&g ...

  6. Nginx 1.5.2 + PHP 5.5.1 + MySQL 5.6.10 在 CentOS 下的编译安装

    最近配置了几台Web服务器,将安装笔记贴出来吧.没时间像以前那样,将文章写的那样系统了,请见谅.详细配置,可以看以前的旧文章: http://blog.zyan.cc/nginx_php_v6 .安装 ...

  7. Hystrix使用Commond的三种方式

    目录(?)[-] 1 依赖引入 2 使用 21 Hystrix command 211 同步执行 212 异步执行 213 反应执行 214 三种模式使用区别 22 Fallback 23 Error ...

  8. FreeRtos——任务删除,改变任务优先级

    以下转载自安富莱电子: http://forum.armfly.com/forum.php vTaskDelete() API 函数任务可以使用 API 函数 vTaskDelete()删除自己或其它 ...

  9. lua工具库penlight--04路径和目录

    使用路径 程序不应该依赖于奇葩的系统,这样你的代码会难以阅读和移植.最糟糕的是硬编码的路径, windows和Unix的路径分隔符正好相反.最好使用path.join,它可以帮助你解决这个问题. pl ...

  10. AM335x 添加 HUAWEI MU609 Mini PCIe Module,并用pppd 启动相关设备

    kernel 的配置 kernel 3.2.0 make menuconfig Device Drivers ---> [*] USB support ---> <*> USB ...