8 Dynamically Managing Cluster Membership

You can programmatically manage cluster and service members and listen to member and service events.

This chapter includes the following sections:

Overview of Managing Cluster Membership

Coherence manages cluster membership by automatically adding new servers to the cluster when they start and automatically detecting their departure when they are shut down or fail. Applications have full access to membership information and can sign up to receive event notifications when members join and leave the cluster. Coherence also tracks all the services that each member is providing and consuming. This information is used to, among other things, plan for service resiliency in case of server failure and to load-balance data management across all members of the cluster.

Using the Cluster and Service Objects

Applications can use local representations of a cluster and cache service to discover important information about a cluster. From any cache, an application can obtain a reference to the local representation of a cache's service. From any service, the application can obtain a reference to the local representation of the cluster.
CacheService service = cache.getCacheService();
Cluster      cluster = service.getCluster();

From the Cluster object, the application can determine the set of services that run in the cluster:

...
for (Enumeration enum = cluster.getServiceNames(); enum.hasMoreElements(); )
    {
    String sName = (String) enum.nextElement();
    ServiceInfo info = cluster.getServiceInfo(sName);
    // ...
    }
...

The ServiceInfo object provides information about the service, including its name, type, version and membership.

Using the Member Object

Applications can use several APIs to discover the members that are part of a cluster, the local member, and the members in a service.The primary information that an application can determine about each member in the cluster is:
  • The Member's IP address
  • What date/time the Member joined the cluster

As an example, if there are four servers in the cluster with each server running one copy ("instance") of the application and all four instances of the application are clustered, then the cluster is composed of four members. From the Cluster object, the application can determine what the local Member is:

Member memberThis = cluster.getLocalMember();

From the Cluster object, the application can also determine the entire set of cluster members:

Set setMembers = cluster.getMemberSet();

From the ServiceInfo object, the application can determine the set of cluster members that are participating in that service:

ServiceInfo info = cluster.getServiceInfo(sName);
Set setMembers = info.getMemberSet();

Listening to Member Events

Applications can listen to cluster and service events to determine membership changes. As of Coherence 14.1.1.2206, remote client membership changes are sent by proxy to all active services configured on the proxy when a remote client joins and leaves the proxy. Applications must implement the MemberListener interface (see Example 8-1). The listener class is then added on a service by either using the addMemberListener method or by adding a <member-listener> element to a cache scheme definition.

There are two advantages to using the configuration approach versus the programmatic approach. First, programmatically, listeners can only be added to a service that is running. As such, the first MEMBER_JOINED event is missed. Secondly, the addMemberListener call must be issued on each and every cluster node that runs the corresponding service. The configuration approach solves both of these issues.

The following example adds a listener implementation named MyMemberListener to a service using the addMemberListener method:

Service service = cache.getCacheService();
service.addMemberListener(package.MyMemberListener);

The service can also be looked up by its name:

Service service = cluster.getService(sName);
service.addMemberListener(package.MyMemberListener);

The following example adds a listener implementation named MyMemberListener to a service named DistributedCache by adding the <member-listener> element to a distributed cache scheme definition:

<distributed-scheme>
   <scheme-name>example-distributed</scheme-name>
   <service-name>DistributedCache</service-name>
   <member-listener>
      <class-name>package.MyMemberListener</class-name>
   </member-listener>
   <backing-map-scheme>
      <local-scheme>
         <scheme-ref>example-binary-backing-map</scheme-ref>
      </local-scheme>
   </backing-map-scheme>
   <autostart>true</autostart>
</distributed-scheme>

The <member-listener> element can be used within the <distributed-scheme>, <replicated-scheme>, <optimistic-scheme>, <invocation-scheme>, and <proxy-scheme> elements. See Cache Configuration Elements.

Note:

A MemberListener implementation must have a public default constructor when using the <member-listener> element to add a listener to a service.

Example 8-1 demonstrates a MemberListener implementation that prints out all the membership events that it receives:

Example 8-1 A Sample MemberListener Implementation

public class MemberEventPrinter
        extends Base
        implements MemberListener
    {
    public void memberJoined(MemberEvent evt)
        {
        out(evt);
        }

    public void memberLeaving(MemberEvent evt)
        {
        out(evt);
        }

    public void memberLeft(MemberEvent evt)
        {
        out(evt);
        }
    }

The MemberEvent object carries information about the event type (either MEMBER_JOINED, MEMBER_LEAVING, or MEMBER_LEFT), the member that generated the event, and the service that acts as the source of the event. Additionally, the event provides a method, isLocal(), that indicates to the application that it is this member that is joining or leaving the cluster. This is useful for recognizing soft restarts in which an application automatically rejoins a cluster after a failure occurs. To distinguish between a cluster member and a remote member joining and leaving the service, see the usage of Member.isRemoteClient() in Example 8-3. If your environment has both cluster members and remote clients using the same service, it might be necessary to take different actions based on the member type. Also, note that since a remote member is not considered a cluster member, these events are not delivered by the proxy to the cluster service.

Note:

Calling the CacheFactory.shutdown() method unregisters all listeners. In this case, both the MEMBER_LEAVING and MEMBER_LEFT events are sent. If a member terminates for any other reason, only the MEMBER_LEFT event is sent.

Example 8-2 illustrates how information encapsulated in a MemberEvent object can be used.

Example 8-2 Using Event Type Information in a MemberEvent Object

public class RejoinEventPrinter
        extends Base
        implements MemberListener
    {
    public void memberJoined(MemberEvent evt)
        {
        if (evt.isLocal())
            {
            out("this member just rejoined the cluster: " + evt);
            }
        }

    public void memberLeaving(MemberEvent evt)
        {
        }

    public void memberLeft(MemberEvent evt)
        {
        }
    }
Example 8-3 illustrates how to identify a remote client MEMBER_JOINED or MEMBER_LEFT.

Example 8-3 Using MemberEvent Objects Member Information to Identify a Remote Client

public class RemoteClientMemberListener
        extends Base
        implements MemberListener
    {
    public void memberJoined(MemberEvent evt)
        {
        Member member = evt.getMember();
        if (member.isRemoteClient())
            {
            out("remote client joined the service.  id=" + member.getUuid());
            }
        }

    public void memberLeaving(MemberEvent evt)
        {
        // Not generated for a remote client.
        }

    public void memberLeft(MemberEvent evt)
        {
        Member member = evt.getMember();
        if (member.isRemoteClient())
            {
            out("remote client left the service.  id=" + member.getUuid());
            }
        }
    }
For the above listener, it conditionally processes remote client membership MEMBER_JOINED and MEMBER_LEFT event when a remote client joins and leaves a proxy. The proxy sends a membership event to all services running on the proxy.

Note:

If the proxy is terminated gracefully or abnormally, a MEMBERED_LEFT MemberEvent is not sent. It is expected that the remote client will rejoin on another proxy. Therefore, no remote client MEMBER_LEFT processing should take place.