• 11.Curator扩展库


        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(" " + 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应用的扩展,本系列将不再介绍了。感兴趣的朋友可以看下面的文档。

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



  • 相关阅读:
    你的服务器和网站为什么会被反复入侵
    MAC 查看当前安装的JDK位置
    Jmeter高并发测试
    解密AndroidManifest.xml、AXMLPrinter2.jar源码下载
    Win10家庭版如何启用本地组策略
    SQLFlow使用中的注意事项--设置篇
    Sqlflow 之隐私政策(Privacy plolicy)介绍
    血缘关系分析工具SQLFLOW--实践指南
    Oracle SQL 性能优化利器
    SQLFlow数据流分析工具的job功能介绍
  • 原文地址:https://www.cnblogs.com/LiZhiW/p/4928964.html
Copyright © 2020-2023  润新知