Skip to content
xuanzhong edited this page Aug 4, 2015 · 36 revisions

##Overview

A Service Directory facility is an essential requirement of a Service Oriented Architecture (SOA). It provides the basis for a Service Provider to register its Service Endpoints such that the attributes required to communicate with the endpoints can be discovered by a Service Consumer which needs to use the service:

Service Directory Overview

###Service Directory Concepts

Some of the concepts and terms used are defined below.

####Service Directory

This is our name for the infrastructure facility providing the aggregate of registration and lookup features.

####Service

An abstraction for a logical business process, uniquely named. The components in a distributed system interact with the service by learning about a specific instance of the service to communicate with. Each instance is implemented by a Service Provider application (which may implement many different service instances). The interface to the service instance is called a Service Endpoint; its representation is standardly encoded in URI format.

####Directory Server

An application, a component of the Service Directory facility, which provides distributed persistence for the Service Directory service instance registrations, plus various lookup features, for its clients. The server is responsible for tracking the health of registered service instances (those intended to be monitored), and to provide means to make service availability visible to its clients, as required. This may include aggregate service availability, as well as instance availability state.

####Service Directory Client

An application which interacts with a Directory Server according to one any of these roles:

  • a Service Directory Provider, which registers one or more services implemented by the application itself;
  • a Service Directory Consumer, which looks up services by name, to obtain information about Service Endpoints it should communicate with;
  • a Service Directory Proxy Provider, a weakened notion of a provider, responsible for registering one or more services which are implemented externally.

####Service Directory API

A library component of the Service Directory facility, providing means for a client to fulfill any (or all) of the above roles.

Beyond providing a convenient, callable interface hiding the details of the communications protocols between client and Directory Server, the API includes a performance-boosting service cache (for highly efficient lookups by consumers), and an efficient heartbeat mechanism for monitoring the availability of provided services. A ServiceDirectory class (static usage, only) provides the entry point for using the features of the Service Directory API, including: configuration, getting references to the functional interfaces for the main Service Directory client roles, and resetting the API (for unit testing).

####Service Instance

A Service Instance is a representation of a named Service Endpoint owned by a Service Provider. It is represented in the API by the class ServiceInstance. ServiceInstance has the name, instance id, URI and metadata info. Principally, once having looked up a Service and retrieving a specific ServiceInstance, the client acting as Service Consumer would use the URI to invoke the function supplied at the specific endpoint of that instance.

Multiple instances of a named service may exist, each sharing the common service name, but with different attributes. Attributes may be intrinsic, modifiable, or provider-defined metadata, and may include:

  • the Service Name, common to all instances of the service (intrinsic);
  • the identity of the application implementing the service instance, i.e. the Service Provider (intrinsic);
  • the Service Endpoint, a URI specifying the means for a client to communicate with the instance (modifiable);
  • the known status of the instance: Up, Down, Unmonitored (modifiable);
  • additional attributes in the form of service meta-data, which may be used to refine the lookups to obtain a subset of service instances.

####Registration Manager

That part of the Service Directory API which supports the roles of Service Directory Provider (and Proxy Provider). The RegistrationManager interface provides methods to register, update and unregister a ServiceInstance. The API's implementation class is responsible for all communications with the Directory Server in support of these features. This includes an optimized heartbeat model to regularly assert the availability of the provider's registered (and monitorable) instances.

####Lookup Manager

That part of the Service Directory API which supports the roles of Service Directory Consumer. The LookupManager interface provides methods for simple ServiceInstance lookups as well as more refined queries. A change notification interface allows a client application to register for a callback when the state of an instance of a specified service has changed.

The API's implementation class is responsible for all comm maintaining the cache of instances previously requested by lookups or queries, based on dynamic change notifications from the Directory Service.

Single-instance lookup supports a default rotational selection mechanism, providing a default client-side load balancing feature.

####Unit Test Framework

It is convenient for application unit testing to not require full-blown integration with an actual Directory Service. In normal API usage, it returns RegistrationManager and LookupManager objects created by an internally initialized default ServiceDirectoryManagerFactory implementation. Their functionality depends on communicating with an actual Directory Service. For unit testing, a client project can use an alternative factory (included in the API), to obtain RegistrationManager and LookupManager objects with a different implementation, maintaining all state in memory thus precluding need to communicate with a DirectoryServer. Applications may extend the alternative implementation to mix-in their own test logic (initializations, assertions, etc.)

##Using the Service Directory API

The preferred project structure for Foundation uses Maven project object model (POM) files to specify how to build and package a project.

The OSS v1.x SD API requires setting up a v1.x Directory Server. For a client project to use the Service Directory API V1.x, the SD API library is specified in the dependency section of the project's pom.xml file:

<dependency>
    <groupId>com.cisco.oss.foundation.directory</groupId>
    <artifactId>sd-api</artifactId>
    <version>1.2.0-0</version>
</dependency>

The following Maven repository for the SD snapshot should be put into your own settings.xml file.

https://oss.sonatype.org/content/repositories/snapshots/com/cisco/oss/foundation

The release versions of the SD API can be found here.

If you are using Ant for your projects, you can download the SD API jars with dependency libraries as a tar ball (sd-api-version.tar.gz): from here.

###API Use Cases

Before using the Service Directory API to connect to the directory server, the API needs to be informed of the location of the Directory Service. Two main configuration settings are used to communicate this to the API:

The server address: DirectoryServiceRestfulClient.SD_API_SD_SERVER_FQDN_PROPERTY, which has default value vcsdirsvc.

The server port: DirectoryServiceRestfulClient.SD_API_SD_SERVER_PORT_PROPERTY, which has default value 2013.

If DirectoryServer is using the default port value, then you only need to insure the server address (first property above) works for your environment.

There are three ways the configuration settings can be made to work for your environment:

a. Define a host alias vcsdirsvc to resolve to the IP where the Directory Service runs. Some production deployments will probably use a DNS (especially where HA Directory Server clusters are fronted by a load balancer exposing a virtual IP). This can also be accomplished by defining the host alias in the /etc/hosts file with the DIR-SVC-IP value, by adding a line like this:

DIR-SVC-IP  vcsdirsvc

In this case, the default address setting will map to the DN which resolves to the desired IP.

b. Another way is to add a file named config.properties in your Java classpath (or found using a path which can be specified to the API - see API javadoc for details). This needs to have (at least) these lines:

com.cisco.oss.foundation.directory.server.fqdn=SERVER-IP-OR-HOSTNAME
com.cisco.oss.foundation.directory.server.port=SERVER-PORT

C. A third way is to use the configuration features of Service Directory API to directly set properties for Directory Service IP or hostname (if it is resolvable), and/or the port number, in code:

ServiceDirectory.getServiceDirectoryConfig().setProperty(
    DirectoryServiceRestfulClient.SD_API_SD_SERVER_FQDN_PROPERTY, "SERVER-IP-OR-HOSTNAME");
ServiceDirectory.getServiceDirectoryConfig().setProperty(
    DirectoryServiceRestfulClient.SD_API_SD_SERVER_PORT_PROPERTY, SERVER-PORT);

The only real advantage of this approach is that your application will now control where the values for SERVER-IP-OR-HOSTNAME and SERVER-PORT come from (i.e. your own property definitions).

Note: A static shutdown() method is provided for the ServiceDirectory class. If ServiceDirectory.shutdown() is called, the SD API will be completely shut down. ServiceDirectory is reusable after the ServiceDirectory.reset() is called.

1. Service registration

// Get a RegistrationManager instance from ServiceDirectory.    
// The ServiceDirectory will load a default ServiceDirectoryConfig and 
// instantialize a RegistrationManager instance.    
RegistrationManager registrationManager = ServiceDirectory.getRegistrationManager();    

// The name of the service    
String serviceName = "odrm-setupsession";    

// IP or the fully qualified host name of the machine which runs the service.    
String address = "10.10.35.7";    

// Construct the service instance. serviceName and address together uniquely 
// identify a service instance.     
ProvidedServiceInstance instance = new ProvidedServiceInstance(serviceName, 
                                                                  address);    

// Setting the service instance URI. 
// URI is defined as tcp://address:port for the TCP end point    
instance.setUri("http://odrm.cisco.net:8090/ndvr/setupsession");    

// By default, the instance status is DOWN    
instance.setStatus(OperationalStatus.UP);  

// Setting the service instance metadata. Optional    
Map<String, String> meta = new HashMap<String, String>();    
meta.put("version", "2.5.0");    
meta.put("datacenter", "datacenter1");    
meta.put("region", "east");    
instance.setMetadata(meta);    

// The port of the service. Optional  
int port = 8090;   
// The TLS port of the service. Optional
int tls_port = 8443;
// Protocol. Optional
String protocol = "http";
instance.setPort(port);
instance.setTls_port(tls_port);
instance.setProtocol(protocol);

// healthCallback is optional, leave it to be null when registering, 
// if the service should not be monitored, e.g. the provider is acting as a proxy.
ServiceInstanceHealth healthCallback = new ServiceInstanceHealth(    
    public boolean isHealthy(){    
    // implementation, skip here.    
    return true;    
    }    
);    

registrationManager.registerService(instance, healthCallback); 
OR    
registrationManager.registerService(instance);

// Update the OperationalStatus of the instance to DOWN, 
// DOWN instance will be removed from lookup.    
registrationManager.updateServiceOperationalStatus(serviceName, 
                  instance.getAddress(), OperationalStatus.DOWN);    

// Update the instance URI
String uri = "http://odrm.cisco.net:8090/ndvr/setupsessionnew";
registrationManager.updateServiceUri(serviceName, 
                                  instance.getAddress(), uri);    

//Update metadata
meta.put("solution-node", "odrm");    
registrationManager.updateServiceMetadata(serviceName, 
                                  instance.getAddress(), meta);    


// Unregister the instance.    
registrationManager.unregisterService(serviceName, instance.getAddress());    

####2. Service Lookup

// Get the LookupManager from ServiceDirectory.    
LookupManager lookupManager = ServiceDirectory.getLookupManager();    

String serviceName = "odrm-setupsession";    

// Simple service lookup, an available (only **UP**) service instance is returned via Round-Robin
// policy from the list of the ServiceInstances    
ServiceInstance serviceInstance1 = lookupManager.lookupInstance(serviceName);    

// Get service endpoint uri    
String uri = instance.getUri();    

// Look up all ServiceInstances (both UP and DOWN) of the Service.    
List<ServiceInstance> allServiceInstances = lookupManager.getInstances(serviceName);    

// Filtering the ServiceInstance via some query criteria on the metadata. 
ServiceInstanceQuery query = new ServiceInstanceQuery()
                              .getEqualQueryCriterion("version", "1.0")
                              .getEqualQueryCriterion("datacenter", "dc01");    

// Returns an available ServiceInstance which matches the query criteria.    
ServiceInstance versionedServiceInstance = lookupManager.queryInstanceByName(serviceName, query);    

// Query all ServiceInstances which match the query criteria.   
List<ServiceInstance> queryedServiceInstances = lookupManager.queryInstancesByName(serviceName, query);    

3. Service Change Callback

// A ServiceInstanceChangeListener interface is provided, and user needs to implement the
// onChange method. Example debug messages are provided as examples.
private ServiceInstanceChangeListener sdCallback = new ServiceInstanceChangeListener () {
    
    public void onChange(ChangeType type, InstanceChange<ServiceInstance> change) {

    switch (type) {
    // An instance is deleted
    case REMOVE:
        LOGGER.debug("Service instance {} has been removed from cache",
                change.from);
        break;
    // A new instance is added
    case ADD:
        LOGGER.debug("Service instance {} has been added to cache.",
                change.to);
        break;
    // There is a status change for the instance UP->DOWN or DOWN->UP
    case STATUS:
        LOGGER.debug(
                "Service instance {} has changed Status from {} to {}",
                change.from.getAddress(), change.from.getStatus(),
                change.to.getStatus());
        break;
    // There is a URI change 
    case URL:
        LOGGER.debug(
                "Service instance {} has changed URL from {} to {}",
                change.from.getAddress(), change.from.getUri(),
                change.to.getUri());
        break;
    // There is meta data change
    case META:
        Map<String, String> map = new HashMap<String, String>();
        map.putAll(change.to.getMetadata());
        LOGGER.debug(
                "Service instance {} has changed Metadata from {} to {}",
                change.from.getAddress(), change.from.getMetadata(),
                map);
        break;
    default:
        break;
    }
};

public void addNotify() throws ServiceException {
    // Add callback to the lookupManager
    LookupManager lookupManager = ServiceDirectory.getLookupManager();
    lookupManager.addInstanceChangeListener(serviceName, sdCallback);  
}

4. Tuning the parameters

The service instance change notification is based on polling mechanism. SD API periodically sends polling requests to the server for any instance changes. The default polling interval is 1s so that any service instance change can be notified timely. The client cache also acts as the service instance change listener, which is updated when there is any service instance change. SD API provides parameters to allow application to turn off the polling or adjust the polling interval.

// Set polling interval
ServiceDirectory.getServiceDirectoryConfig().setProperty(    
    DirectoryLookupService.SD_API_POLLING_DELAY_PROPERTY, 10);    

// Disable client cache
ServiceDirectory.getServiceDirectoryConfig().setProperty(
     ServiceDirectoryConfig.SD_API_CACHE_ENABLED_PROPERTY, false);
Clone this wiki locally