CORBA Load Balancing Assignment

In this assignment, you will implement a load balancing service using CORBA. Client applications can use this service to treat a group of Objects as an equivalence class to improve distributed load balancing.

In this service, CORBA remote operations are used to create Object_Groups that use various policies, such as round robin or random, to balance client load. In addition, servers use to bind and unbind operations to populate an Object_Group with a group of Members, which are typically CORBA Objects that form an equivalence class of implementations for a particular service.

Client applications use CORBA operations implemented by the Object_Group to resolve requests for arbitrary Members. The order in which the requests are resolved, i.e., in round robin or random order, depends on the policy that the Object_Group was created with by an Object_Group_Factory.


Design and Implementation Issues

CORBA IDL Interface

The CORBA load balancing service is defined by the following IDL specification:
module Load_Balancer
{
  // = TITLE
  //   Define a module for CORBA that allows clients to treat a group
  //   of <Object>s, i.e., an <Object_Group>, as an equivalence class
  //   to improve distributed load balancing.
  //
  // = DESCRIPTION
  //   This module supports type types of load balancing
  //   <Object_Group>s: 
  //   
  //   1. <Round_Robin_Object_Group> -- This <Object_Group> resolves
  //      requests for arbitrary members in round robin order.
  //
  //   2. <Random_Object_Group> -- This <Object_Group> resolves
  //      requests for arbitrary members in random order.

  // = Module-defined exceptions.
  exception no_such_member {};
  exception duplicate_member {};
  exception duplicate_group {};
  exception no_such_group {};

  // = Module-defined types.
  typedef string Member_ID;
  typedef sequence<Member_ID> Member_ID_List;

  struct Member
  {
    Object obj;
    // IOR to the object that's a member in the <Object_Group>.

    Member_ID id;
    // Each <Member> in an <Object_Group> has its own unique ID.
  };

  typedef string Group_ID;
  typedef sequence<Group_ID> Group_List;

  // = Forward interface decls.
  interface Object_Group;
  interface Round_Robin_Object_Group;
  interface Random_Object_Group;

  interface Object_Group_Factory
    {
      // = TITLE
      //   A factory that creates the appropriate type of
      //   <Object_Group>. 
      // 
      // = DESCRIPTION
      //   Currently, two types of <Object_Group>s are defined.  One
      //   resolves requests for arbitrary members in round robin
      //   order and the other resolves requests for arbitrary members
      //   in random order.

      Round_Robin_Object_Group make_round_robin (in Group_ID id)
        raises (duplicate_group);
      // Create an <Object_Group> that resolves requests for arbitrary
      // members in round robin order.

      Random_Object_Group make_random (in Group_ID id)
        raises (duplicate_group);
      // Create an <Object_Group> that resolves requests for arbitrary
      // members in random order.

      Object_Group resolve (in Group_ID id) raises (no_such_group);
      // Locate and return an <Object_Group> by its <Group_ID>.

      Group_List round_robin_groups ();
      // Returns a sequence of the <Round_Robin_Object_Group>s.

      Group_List random_groups ();
      // Returns a sequence of the <Random_Object_Group>s.
    };

  interface Object_Group
    {
      readonly attribute string id;
      // Each Object Group has its own distinct member ID. 

      void bind (in Member member) raises (duplicate_member);
      // Add a new <member> to the <Object_Group>.  Note that each
      // <Member_ID> in an <Object_Group> must be unique.

      void unbind (in Member_ID id) raises (no_such_member);
      // Remove a particular <Member_ID> from the <Object_Group>.

      Object resolve () raises (no_such_member);
      // Returns any <Member> in the <Object_Group> in accordance with
      // the appropriate load balancing policy, i.e., ``random'' or
      // ``round robin.''
		
      Object resolve_with_id (in Member_ID id) raises (no_such_member);
      // Locate and return an <Object> in the <Object_Group> according
      // to its <Member_ID>.

      Member_ID_List members ();
      // Return a sequence of the <Member>s in the <Object_Group>.

      void destroy ();
      // Cleanup the resources associated with the <Object_Group>.
      // Subsequent calls to this <Object_Group> should fail.
    };
		
  interface Random_Object_Group : Object_Group 
    {
      // = TITLE

      //   Implement an <Object_Group> that resolves requests for
      //   arbitrary members in random order.
    };

  interface Round_Robin_Object_Group : Object_Group 
    {
      // = TITLE

      //   Implement an <Object_Group> that resolves requests for
      //   arbitrary members in round robin order.
    };
};
You will use the TAO IDL compiler to translate this specification into client-side stubs and server-side skeletons. The client application (which you must write) will use the stubs as a proxy to access the load balancing service implemented by a server (which you also must write). In addition, you'll need to register Objects with the load balancer. For the purposes of this assignment, please you use various instances of the Time/Date server from your previous assignment.

Object Group Server Functionality

On the server-side, you'll need to define several classes that inherit from the skeletons generated by the IDL compiler. These C++ classes should look something like the following:

// Implement the Object_Group_Factory

class Object_Group_Factory_i : virtual public POA_Load_Balancer::Object_Group_Factory
{
public:
  // ... You fill in here...
};

// Implement the various types of Object Groups.

class Random_Object_Group_i : virtual public POA_Load_Balancer::Random_Object_Group
{
public:
  // ... You fill in here...
};

class Round_Robin_Object_Group_i : virtual public POA_Load_Balancer::Round_Robin_Object_Group
{
public:
  // ... You fill in here...
};
To implement Random_Object_Group_i you'll need to use the ACE_OS::rand and ACE_OS::srand APIs. I recommend that you check the UNIX manual pages for more details on using these functions.

In addition, you'll need to implement a main function that defines an instance of Object_Group_Factory_i, obtains and activates the RootPOA and then calls the ORB's run method to start the event loop.

Time/Date Server Functionality

In order to have some Object to put into Object_Groups, please modify the Time/Date server from your previous assignment to (1) obtain an object reference to the Object_Group_Factory from a file, (2) use the factory to obtain the appropriate type of load balancing service, i.e., random or round robin, based on the type of make_* Factory Method invoked, and (3) bind the object reference to its Time_Date object with this service. By creating several instances of the Time/Date server with different object references, you'll be able to test out the load balancing service via your test client (described below).

Client Functionality

The client can also be based on extensions to the client application used in your previous assignment. However, rather than getting the object reference to the server from a file, it will get the object reference of the Object_Group_Factory from a file. It can use this factory to obtain an object reference to appropriate type of load balancing service in several ways: In either case, once the client has an object reference, it can then call resolve on the Object_Group to locate an appropriate Time_Date object. At this point, it will behave like it did in the previous assignment.

Invoking the Client and Server

Once the client and server components are written, compiled, and linked you'll need to get the client and the two servers to work together. To make your life easy, the Object Group server should write its IOR to a file (later, we'll use more advanced techniques, such as a Naming Service). Thus, when your server is started, you should create a file that contains something like the following:

iiop:1.0//danzon.cs.wustl.edu:10015/P35ad159600081a38/server
if you use the -ORBobjrefstyle url IOR format or
IOR:000000000000001649444c3a43756269745...
If you use the -ORBobjrefstyle ior IOR format.

When the client or the Time/Date servers start up, they will read the contents of the file into a string and use the string_to_object method to convert the string into an object reference. This object reference will then be downcast via _narrow to an object reference for the Object_Group_Factory interface. At this point, follow the instructions above to obtain an object reference to the appropriate type of load balancing service.


Using CORBA

We will be using the TAO CORBA Object Request Broker (ORB) implementation. Please see the online help for information on how to setup your TAO development environment on Washington University's computing system.


Concluding Remarks

This CORBA assignment is harder than the previous one. It will help build more sophisticated skills necessary to become adept at distributed object computing with CORBA.

Last modified 14:08:45 CDT 25 April 1999