服务发现
服务发现主要应用于微服务架构和分布式架构场景下。在这些场景下,一个服务通常需要松耦合的多 个组件的协同才能完成。服务发现就是让组件发现相关的组件。服务发现要提供的功能有以下3点:
- 服务注册。
- 服务实例的获取。
- 服务变化的通知机制。 Curator 有一个扩展叫作 curator-x-discovery。curator-x-discovery 基于 ZooKeeper 实现了服务发现。
curator-x-discovery设计
使用一个base path作为整个服务发现的根目录。在这个根目录下是各个服务的的目录。服务目录下面是服务实例。实例是服务实例的JSON序列化数据。服务实例对应的znode节点可以根据需要设置成持久性、临时性和顺序性。
下图列出了服务发现用户代码使用的curator-x-discovery接口。最主要的有以下三个接口:
- ServiceProvider:在服务cache之上支持服务发现操作,封装了一些服务发现策略。
- ServiceDiscovery:服务注册,也支持直接访问ZooKeeper的服务发现操作。
- ServiceCache:服务cache。
curator-x-discovery主要类
- ServiceInstance 用来表示服务实例的POJO,除了包含一些服务实例常用的成员之外,还提供一个payload成员让用 户存自定义的信息。
private final String name;
private final String id;
private final String address;
private final Integer port;
private final Integer sslPort;
private final T payload;
private final long registrationTimeUTC;
private final ServiceType serviceType;
private final UriSpec uriSpec;
private final boolean enabled;
- ServiceDiscovery 从一个ServiceDiscovery,可以创建多个ServiceProvider和多个ServiceCache。
- ServiceProvider ServiceProvider 提供服务发现 high-level API。ServiceProvider 是封装ProviderStraegy 和InstanceProvider的facade。InstanceProvider的数据来自一个服务 Cache。 服务cache是ZooKeeper数据的一个本地cache,服务cache里面的数据可能会比ZooKeeper里面的数据旧一些。ProviderStraegy提供了三种策略:轮询,随机和sticky。
ServiceProvider除了提供服务发现的方法(getlnstance和getAllnstances )以外,还通过noteError提供了一个让服务使用者把服务使用情况反馈给ServiceProvider的机制。
- ServiceCache
public interface ServiceCache<T> extends Closeable, Listenable<ServiceCacheListener>, InstanceProvider<T>
{
/**
* Return the current list of instances. NOTE: there is no guarantee of freshness. This is
* merely the last known list of instances. However, the list is updated via a ZooKeeper watcher
* so it should be fresh within a window of a second or two.
*
* @return the list
*/
public List<ServiceInstance<T>> getInstances();
/**
* The cache must be started before use
*
* @throws Exception errors
*/
public void start() throws Exception;
CountDownLatch startImmediate() throws Exception;
}
与ZooKeeper交互
ServiceDiscovery提供的服务注册方法是对znode的更新操作,服务发现方法是znode的读取操作。
同时它也是最核心的类,所有的服务发现操作都要从这个类开始。
另外服务Cache会接受来自ZooKeeper的更新通知,读取服务信息(也就是读取znode信息)。
ServiceDiscovery ServiceCache Serviceprovider 说明
- 都有一个对应的builder。这些builder提供一个创建这三个类的fluent API。
- 在使用之前都要调用start方法。
- 在使用之后都要调用close方法。close方法只会释放自己创建的资源,不会释放上游关联的资源。例如 ServiceDiscovery 的 close 方法不会去调用 CuratorFramework 的 close 方法。 示例代码
/** Shows the basic usage for curator-x-discovery. */
@Test
public void testBasics() throws Exception {
CuratorFramework client = null;
ServiceDiscovery<String> discovery = null;
ServiceProvider<String> provider = null;
String serviceName = "test";
String basePath = "/services";
try {
client = CuratorFrameworkFactory.newClient(connectString, new RetryOneTime(1));
client.start();
ServiceInstance<String> instance1 =
ServiceInstance.<String>builder().payload("plant").name(serviceName).port(10064).build();
ServiceInstance<String> instance2 =
ServiceInstance.<String>builder().payload("animal").name(serviceName).port(10065).build();
System.out.printf("instance1 id: %s\n", instance1.getId());
System.out.printf("instance2 id: %s\n", instance2.getId());
discovery =
ServiceDiscoveryBuilder.builder(String.class)
.basePath(basePath)
.client(client)
.thisInstance(instance1)
.build();
discovery.start();
discovery.registerService(instance2);
provider = discovery.serviceProviderBuilder().serviceName(serviceName).build();
provider.start();
assertThat(provider.getInstance().getId()).isNotEmpty();
assertThat(provider.getAllInstances()).containsExactly(instance1, instance2);
client.delete().deletingChildrenIfNeeded().forPath(basePath);
} finally {
CloseableUtils.closeQuietly(provider);
CloseableUtils.closeQuietly(discovery);
CloseableUtils.closeQuietly(client);
}
}