All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jabb.util.parallel.ClusteredLoadBalancer Maven / Gradle / Ivy

There is a newer version: 1.0.73
Show newest version
/**
 * 
 */
package net.sf.jabb.util.parallel;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.ToIntFunction;

import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.View;
import org.jgroups.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Throwables;

/**
 * Load balancer clustered using jgroups for dispatching work loads to networked processing nodes.
 * Changes made to one instance will be propagated to all the member instances in the cluster.
 * @author James Hu
 *
 */
public class ClusteredLoadBalancer extends BasicLoadBalancer {
	private static final Logger logger = LoggerFactory.getLogger(ClusteredLoadBalancer.class);
	protected JChannel channel;
	
	
	/**
	 * Constructor
	 * @param channel		the jgroups channel
	 * @param clusterName	the cluster name for the jgroups channel
	 * @param buckets	number of buckets for distributing the load evenly, normally it should be at least 10 times bigger than the number of processors.
	 * @param activeProcessors  processors, there must not be duplicated elements
	 * @param hashFunction	the function to create hash code for the work load dispatching
	 * @param dispatcher	actual dispatcher
	 */
	public ClusteredLoadBalancer(JChannel channel, String clusterName, int buckets, Collection

activeProcessors, ToIntFunction hashFunction, BiFunction dispatcher){ this(channel, clusterName, buckets, activeProcessors, null, null, hashFunction, dispatcher, null, null); } /** * Constructor * @param channel the jgroups channel * @param clusterName the cluster name for the jgroups channel * @param buckets number of buckets for distributing the load evenly, normally it should be at least 10 times bigger than the number of processors. * @param activeProcessors processors, there must not be duplicated elements * @param backupProcessors backup processors which will not be used at the beginning, there must not be duplicated elements. It can be null. * @param fallback the fall back processor that handles all the failed-to-dispatch work loads. It can be null. * @param hashFunction the function to create hash code for the work load dispatching * @param dispatcher actual dispatcher * @param statistics statistics collector. It can be null. * @param monitor monitor that receives copies of all of the work load. It can be null. */ public ClusteredLoadBalancer(JChannel channel, String clusterName, int buckets, Collection

activeProcessors, Collection

backupProcessors, Consumer fallback, ToIntFunction hashFunction, BiFunction dispatcher, Consumer> statistics, Consumer monitor){ super(buckets, activeProcessors, backupProcessors, fallback, hashFunction, dispatcher, statistics, monitor); this.channel = channel; channel.setReceiver(new Receiver()); try { channel.connect(clusterName); } catch (Exception e) { logger.error("Unable to connect to cluster '{}' through channel: {}", clusterName, channel, e); Throwables.propagate(e); } } public View getClusterView(){ return channel.getView(); } @Override public void finalize(){ channel.close(); } synchronized protected void setState(StateData

stateData){ if (stateData.getProcessorMap() != null){ this.processorMap = stateData.getProcessorMap(); } if (stateData.getActiveProcessors() != null){ this.activeProcessors = stateData.getActiveProcessors(); } if (stateData.getBackupProcessors() != null){ this.backupProcessors = stateData.getBackupProcessors(); } } synchronized protected StateData

getState(boolean withProcessorMap, boolean withActiveProcessors, boolean withBackupProcessors){ return new StateData

(withProcessorMap ? null : processorMap, withActiveProcessors ? null : activeProcessors, withBackupProcessors ? null : backupProcessors); } protected StateData

getState(){ return getState(true, true, true); } /** * Propagate state to other members in the cluster * @param withProcessorMap whether to propagate processorMap * @param withActiveProcessors whether to propagate activeProcessors * @param withBackupProcessors whether to propagate backupProcessors */ protected void propagateState(boolean withProcessorMap, boolean withActiveProcessors, boolean withBackupProcessors){ try { channel.send(null, getState(withProcessorMap, withActiveProcessors, withBackupProcessors)); } catch (Exception e) { logger.error("Unable to propagate state through channel: {}", channel, e); } } /** * Propagate full state to other members in the cluster */ protected void propagateState(){ propagateState(true, true, true); } protected class Receiver extends ReceiverAdapter{ @Override public void receive(Message msg){ try { Object payload = Util.objectFromByteBuffer(msg.getBuffer()); if (payload instanceof StateData){ @SuppressWarnings("unchecked") StateData

stateData = (StateData

) payload; ClusteredLoadBalancer.this.setState(stateData); } } catch (Exception e) { logger.error("Error when receiving and processing received massage: {}", msg, e); } } @Override public void getState(OutputStream output) throws Exception { synchronized(ClusteredLoadBalancer.this){ Util.objectToStream(ClusteredLoadBalancer.this.getState(), new DataOutputStream(output)); } } @SuppressWarnings("unchecked") @Override public void setState(InputStream input) throws Exception { synchronized(ClusteredLoadBalancer.this){ ClusteredLoadBalancer.this.setState((StateData

) Util.objectFromStream(new DataInputStream(input))); } } } /** * Data needed for state replication * @author James Hu * * @param

type of the processor */ public static class StateData

implements Serializable{ private static final long serialVersionUID = 7186584292417807338L; protected Object[] processorMap; protected List

activeProcessors; protected List

backupProcessors; public StateData(){ } public StateData(Object[] processorMap, List

activeProcessors, List

backupProcessors){ this(); this.processorMap = processorMap; this.activeProcessors = activeProcessors; this.backupProcessors = backupProcessors; } public Object[] getProcessorMap() { return processorMap; } public void setProcessorMap(Object[] processorMap) { this.processorMap = processorMap; } public List

getActiveProcessors() { return activeProcessors; } public void setActiveProcessors(List

activeProcessors) { this.activeProcessors = activeProcessors; } public List

getBackupProcessors() { return backupProcessors; } public void setBackupProcessors(List

backupProcessors) { this.backupProcessors = backupProcessors; } } /** * Increase the load of a processor * @param processor the processor * @param percentageDelta the percentage of load in total that will be increased */ @Override synchronized public void increaseLoad(P processor, float percentageDelta){ super.increaseLoad(processor, percentageDelta); propagateState(true, false, false); } /** * Decrease the load of a processor * @param processor the processor * @param percentageDelta the percentage of load in total that will be decreased */ @Override synchronized public void decreaseLoad(P processor, float percentageDelta){ super.decreaseLoad(processor, percentageDelta); propagateState(true, false, false); } /** * Add a processor. Work load will be dispatched to the newly added processor immediately. * @param processor the processor */ @Override synchronized public void add(P processor){ super.add(processor); propagateState(true, true, false); } /** * Remove a processor. The dispatcher will stop dispatching work load to the newly removed processor immediately. * @param processor the processor */ @Override synchronized public void remove(P processor){ super.remove(processor); propagateState(true, true, false); } /** * Add a backup processor * @param processor the backup processor */ @Override synchronized public void addBackup(P processor){ super.addBackup(processor); propagateState(false, false, true); } /** * Remove a backup processor * @param processor the backup processor */ @Override synchronized public void removeBackup(P processor){ super.removeBackup(processor); propagateState(false, false, true); } /** * Promote a backup processor to active * @param processor the backup processor */ @Override synchronized public void promote(P processor){ super.promote(processor); propagateState(); } /** * Demote an active processor to backup * @param processor the active processor */ @Override synchronized public void demote(P processor){ super.demote(processor); propagateState(); } /** * Replace an active processor with another new processor * @param processor the processor to be replaced * @param newProcessor the new processor */ @Override synchronized public void replace(P processor, P newProcessor){ super.replace(processor, newProcessor); propagateState(true, true, false); } /** * Replace a backup processor with another new processor * @param processor the backup processor to be replaced * @param newProcessor the new processor */ @Override synchronized public void replaceBackup(P processor, P newProcessor){ super.replaceBackup(processor, newProcessor); propagateState(false, false, true); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy