Difference between revisions of "Load Balancing Remote Services"

From Eclipsepedia

Jump to: navigation, search
(Service Server)
 
(9 intermediate revisions by one user not shown)
Line 7: Line 7:
 
ECF now has an example that uses the [http://github.com/ECF/JMS ECF ActiveMQ provider] to dynamically load balance individual service requests to an arbitrary number of server processes, thereby distributing the load caused by the service requests onto as many server processes as can be made available.  The actual load balancing of individual requests is done by using a [http://en.wikipedia.org/wiki/Java_Message_Service JMS Queue], which has load balancing semantics built in.   
 
ECF now has an example that uses the [http://github.com/ECF/JMS ECF ActiveMQ provider] to dynamically load balance individual service requests to an arbitrary number of server processes, thereby distributing the load caused by the service requests onto as many server processes as can be made available.  The actual load balancing of individual requests is done by using a [http://en.wikipedia.org/wiki/Java_Message_Service JMS Queue], which has load balancing semantics built in.   
  
The load balancing example projects are available in CVS:
+
The load balancing example projects are available in git here
  
CVS root: '''/cvsroot/rt'''
+
http://git.eclipse.org/c/ecf/org.eclipse.ecf.git
  
module:  '''org.eclipse.ecf/examples/bundles'''
+
under this part of the tree:  '''examples/bundles'''
  
 
projects:  '''org.eclipse.ecf.examples.loadbalancing''', '''org.eclipse.ecf.examples.loadbalancing.consumer''', '''org.eclipse.ecf.examples.loadbalancing.servicehost''', '''org.eclipse.ecf.examples.loadbalancing.server'''
 
projects:  '''org.eclipse.ecf.examples.loadbalancing''', '''org.eclipse.ecf.examples.loadbalancing.consumer''', '''org.eclipse.ecf.examples.loadbalancing.servicehost''', '''org.eclipse.ecf.examples.loadbalancing.server'''
  
Or you can use this [http://wiki.eclipse.org/images/6/6d/Examples.loadbalancing.psf project set file] to load the 4 example projects into directly into your Eclipse workspace.
+
Note that you either need to have ECF 3.6.X already installed, or install it in Eclipse or into your workspace's target platform.  See [http://www.eclipse.org/ecf/downloads.php here] to download/install ECF 3.6.X
 
+
Note that you either need to have ECF 3.1 already installed, or install it in Eclipse or into your workspace's target platform.  See [http://www.eclipse.org/ecf/downloads.php here] to download/install ECF 3.1.
+
  
 
===Architecture===
 
===Architecture===
Line 46: Line 44:
 
====Starting and Configuring ActiveMQ====
 
====Starting and Configuring ActiveMQ====
  
# To run the example, it's necessary to first install [http://activemq.apache.org/download.html ActiveMQ 5.2].  Once installed, start ActiveMQ by going to the '''<activemq home>/bin''' directory, and starting ActiveMQ by giving the '''activemq''' command in the <activemq home>/bin directory.  This will start an instance of ActiveMQ 5.2.
+
# To run the example, it's necessary to first install [http://activemq.apache.org/download.html ActiveMQ 5.2+].  Once installed, start ActiveMQ by going to the '''<activemq home>''' directory, and starting ActiveMQ by giving the '''bin\activemq''' command in the <activemq home> directory.  This will start an instance of ActiveMQ 5.2+.
 
# With your web browser, go to the ActiveMQ web-based admin interface (by default:'''http://localhost:8161/admin''')
 
# With your web browser, go to the ActiveMQ web-based admin interface (by default:'''http://localhost:8161/admin''')
 
# Use the admin interface create a JMS queue with the following name:  '''exampleQueue'''
 
# Use the admin interface create a JMS queue with the following name:  '''exampleQueue'''
Line 59: Line 57:
  
 
<pre>
 
<pre>
 +
osgi> SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 +
SLF4J: Defaulting to no-operation (NOP) logger implementation
 +
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 
LB Server:  Data Processor Registered queue=tcp://localhost:61616/exampleQueue
 
LB Server:  Data Processor Registered queue=tcp://localhost:61616/exampleQueue
 
</pre>
 
</pre>
Line 70: Line 71:
  
 
<pre>
 
<pre>
<ActiveMQ 5.2 spurious WARNING and exception stack...see ActiveMQ bug: https://issues.apache.org/activemq/browse/AMQ-2256>
+
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
LB Service Host: DataProcessor Registered via ECF Remote Services topic=tcp://localhost:61616/exampleTopic
+
SLF4J: Defaulting to no-operation (NOP) logger implementation
 +
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 +
osgi> LB Service Host: DataProcessor Registered via ECF Remote Services topic=tcp://localhost:61616/exampleTopic
 
</pre>
 
</pre>
  
Line 82: Line 85:
  
 
<pre>
 
<pre>
<ActiveMQ 5.2 spurious WARNING and exception stack...see ActiveMQ bug:  https://issues.apache.org/activemq/browse/AMQ-2256>
+
osgi> SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
RemoteServiceTracker.Tracked.serviceChanged[class org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject$6]: RemoteServiceReferenceImpl[class=null;registration=RemoteServiceRegistrationImpl[remoteServiceID=org.eclipse.ecf.remoteservice.RemoteServiceID[containerID=JMSID[tcp://localhost:61616/exampleTopic];containerRelativeID=0];containerID=JMSID[tcp://localhost:61616/exampleTopic];serviceid=0;serviceranking=0;classes=[org.eclipse.ecf.examples.loadbalancing.IDataProcessor];state=0;properties={ecf.rsvc.proxy=true, ecf.rsvc.id=0}]]
+
SLF4J: Defaulting to no-operation (NOP) logger implementation
RemoteServiceTracker.Tracked.trackAdding: RemoteServiceReferenceImpl[class=null;registration=RemoteServiceRegistrationImpl[remoteServiceID=org.eclipse.ecf.remoteservice.RemoteServiceID[containerID=JMSID[tcp://localhost:61616/exampleTopic];containerRelativeID=0];containerID=JMSID[tcp://localhost:61616/exampleTopic];serviceid=0;serviceranking=0;classes=[org.eclipse.ecf.examples.loadbalancing.IDataProcessor];state=0;properties={ecf.rsvc.proxy=true, ecf.rsvc.id=0}]]
+
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 
Calling remote service with input data=Are we not drawn onward, we few, drawn onward to new era  
 
Calling remote service with input data=Are we not drawn onward, we few, drawn onward to new era  
 
remote service result= are wen ot drawno nward ,wef ew ,drawno nward ton ew erA
 
remote service result= are wen ot drawno nward ,wef ew ,drawno nward ton ew erA
Line 94: Line 97:
  
 
<pre>
 
<pre>
DataProcessorImpl(Vf/B9giiOv3dCEQrAVKPrREJgBY=).processData data=Are we not drawn onward, we few, drawn onward to new era  
+
DataProcessorImpl(7MpbrpeWXUZHDElu681E5er7VRw=).processData data=Are we not drawn onward, we few, drawn onward to new era  
 
</pre>
 
</pre>
  
Line 102: Line 105:
  
 
=====Service Server=====
 
=====Service Server=====
'''org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorServerApplication'''
 
 
'''org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorImpl'''
 
'''org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorImpl'''
 +
<pre>
 +
public class DataProcessorImpl implements IDataProcessor {
 +
 +
private ID containerID;
 +
 +
public DataProcessorImpl(ID containerID) {
 +
this.containerID = containerID;
 +
}
 +
 +
/**
 +
* Entry point for IDataProcessor service implementation
 +
*/
 +
public String processData(String data) {
 +
System.out.println("DataProcessorImpl(" + containerID.getName()
 +
+ ").processData data=" + data);
 +
if (data == null) return null;
 +
return reverseString(data);
 +
}
 +
 +
private String reverseString(String data) {
 +
StringBuffer buf = new StringBuffer(data);
 +
buf.reverse();
 +
return buf.toString();
 +
}
 +
 +
public void stop() {
 +
}
 +
 +
}
 +
</pre>
 +
 +
'''org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorServerApplication'''
  
 
=====Service Host=====
 
=====Service Host=====

Latest revision as of 13:21, 11 September 2013

Contents

[edit] Load Balancing ECF Remote Services

ECF's remote services API allows arbitrary services to be exposed for remote access/invocation.

In some cases, such services will be long-running and/or computationally intensive, and this can mean that multiple servers can/should be used to actually execute the given service, so as not to use all resource available on a given server. What would be desirable is that the actual remote service request be dynamically load balanced among some arbitary number of servers, so as not to overload a given server instance.

ECF now has an example that uses the ECF ActiveMQ provider to dynamically load balance individual service requests to an arbitrary number of server processes, thereby distributing the load caused by the service requests onto as many server processes as can be made available. The actual load balancing of individual requests is done by using a JMS Queue, which has load balancing semantics built in.

The load balancing example projects are available in git here

http://git.eclipse.org/c/ecf/org.eclipse.ecf.git

under this part of the tree: examples/bundles

projects: org.eclipse.ecf.examples.loadbalancing, org.eclipse.ecf.examples.loadbalancing.consumer, org.eclipse.ecf.examples.loadbalancing.servicehost, org.eclipse.ecf.examples.loadbalancing.server

Note that you either need to have ECF 3.6.X already installed, or install it in Eclipse or into your workspace's target platform. See here to download/install ECF 3.6.X

[edit] Architecture

The load balancing example application starts with a very simple, stateless, service interface called IDataProcessor:

public interface IDataProcessor {

    public String processData(String data);
}

This is a very simple service interface, and is meant to be illustrative/example only. Other services will/should be created as appropriate for one's own application.

The load balancing application is structured as follows:

  1. One or more Service Consumers. The service consumer is the actual client of the remote service (in this case, the client of IDataProcessor service).
  2. A single Service Host, which appears to clients as the actual host of the IDataProcessor service, but is actually a JMS queue producer, which puts method invocation requests (received from the consumers) onto a JMS queue.
  3. One or more Service Servers. The service servers are JMS queue message consumers, so that when a service request is put into the JMS queue, it is then delivered to one and only one queue consumers (as per the JMS Queue semantics). Once received, the appropriate method is invoked on a target service implementation object.

The inter-process communication pattern for these three processes is as follows:

Service Consumer(s) <-JMS topic-> Service Host <-JMS Queue-> Service Server(s)

[edit] Running the Example

[edit] Starting and Configuring ActiveMQ

  1. To run the example, it's necessary to first install ActiveMQ 5.2+. Once installed, start ActiveMQ by going to the <activemq home> directory, and starting ActiveMQ by giving the bin\activemq command in the <activemq home> directory. This will start an instance of ActiveMQ 5.2+.
  2. With your web browser, go to the ActiveMQ web-based admin interface (by default:http://localhost:8161/admin)
  3. Use the admin interface create a JMS queue with the following name: exampleQueue
  4. Use the admin interface to create a JMS topic with the following name: exampleTopic

[edit] Starting the Service Server(s)

  1. In the org.eclipse.ecf.examples.loadbalancing.server project, open the product config by double clicking on the products/Data Processor Server (activemq).product file in the Eclipse package explorer or the navigator. This should open the Eclipse product configuration editor.
  2. In the lower left of the Overview tab, click on the Launch an Eclipse application or the Launch an Eclipse application in Debug mode links. This should launch the data processor server. Note you can start multiple server instances, but you should have at least one running before starting the service host.

On startup, the service server should produce output to the console like this

osgi> SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
LB Server:  Data Processor Registered queue=tcp://localhost:61616/exampleQueue

[edit] Starting the Service Host

  1. In the org.eclipse.ecf.examples.loadbalancing.servicehost project, open the product config by double clicking on the products/Data Processor Service Host (activemq).product file in the Eclipse package explorer or the navigator. This should open the Eclipse product configuration editor.
  2. In the lower left of the Overview tab, click on the Launch an Eclipse application or the Launch an Eclipse application in Debug mode links. This should launch the data processor service host. You should start only a single service host.

On startup, the service host should produce output to the console like this

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
osgi> LB Service Host: DataProcessor Registered via ECF Remote Services topic=tcp://localhost:61616/exampleTopic

[edit] Running the Service Consumer

  1. In the org.eclipse.ecf.examples.loadbalancing.consumer project, open the product config by double clicking on the products/Data Processor Consumer (activemq).product file in the Eclipse package explorer or the navigator. This should open the Eclipse product configuration editor.
  2. In the lower left of the Overview tab, click on the Launch an Eclipse application or the Launch an Eclipse application in Debug mode links. This should launch the data processor service consumer application.

On startup, the service consumer should produce output to the console like this

osgi> SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Calling remote service with input data=Are we not drawn onward, we few, drawn onward to new era 
	remote service result= are wen ot drawno nward ,wef ew ,drawno nward ton ew erA

The last couple of lines show that the remote IDataProcessor service was invoked with the input data, and produced the given result (reversing the inputData String).

Also, if the Service Server console is consulted after running the Service Consumer, you should see the output of remote call of the Service Server implementation object:

DataProcessorImpl(7MpbrpeWXUZHDElu681E5er7VRw=).processData data=Are we not drawn onward, we few, drawn onward to new era 

If more than one Service Server is started, then each consumer invocation will be load balanced among the Service Servers.

[edit] Classes to examine in source

[edit] Service Server

org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorImpl

public class DataProcessorImpl implements IDataProcessor {

	private ID containerID;

	public DataProcessorImpl(ID containerID) {
		this.containerID = containerID;
	}

	/**
	 * Entry point for IDataProcessor service implementation
	 */
	public String processData(String data) {
		System.out.println("DataProcessorImpl(" + containerID.getName()
				+ ").processData data=" + data);
		if (data == null) return null;
		return reverseString(data);
	}

	private String reverseString(String data) {
		StringBuffer buf = new StringBuffer(data);
		buf.reverse();
		return buf.toString();
	}

	public void stop() {
	}

}

org.eclipse.ecf.internal.examples.loadbalancing.server.DataProcessorServerApplication

[edit] Service Host

org.eclipse.ecf.internal.examples.loadbalancing.servicehost.DataProcessorServiceHostApplication

[edit] Service Consumer

org.eclipse.ecf.internal.examples.loadbalancing.consumer.DataProcessorConsumerApplication