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

netflix.ocelli.loadbalancer.ChoiceOfTwoLoadBalancer Maven / Gradle / Ivy

There is a newer version: 0.1.0-rc.2
Show newest version
package netflix.ocelli.loadbalancer;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;

import netflix.ocelli.LoadBalancer;
import rx.Subscriber;
import rx.functions.Func2;

/**
 * This selector chooses 2 random hosts and picks the host with the 'best' 
 * performance where that determination is deferred to a customizable function.
 * 
 * This implementation is based on the paper 'The Power of Two Choices in 
 * Randomized Load Balancing' http://www.eecs.harvard.edu/~michaelm/postscripts/tpds2001.pdf
 * This paper states that selecting the best of 2 random servers results in an 
 * exponential improvement over selecting a single random node (also includes
 * round robin) but that adding a third (or more) servers does not yield a significant
 * performance improvement.
 * 
 * @author elandau
 *
 * @param 
 */
public class ChoiceOfTwoLoadBalancer extends LoadBalancer {
    public static  ChoiceOfTwoLoadBalancer create(final Func2 func) {
        return new ChoiceOfTwoLoadBalancer(func);
    }

    private final AtomicReference> clients;
    
    ChoiceOfTwoLoadBalancer(final Func2 func) {
        this(func, new AtomicReference>(new ArrayList()));
    }
    
    private ChoiceOfTwoLoadBalancer(final Func2 func, final AtomicReference> clients) {
        super(new OnSubscribe() {
            private final Random rand = new Random();
            
            @Override
            public void call(final Subscriber s) {
                List local = clients.get();
                if (local.isEmpty()) {
                    s.onError(new NoSuchElementException("No servers available in the load balancer"));
                }
                else if (local.size() == 1) {
                    s.onNext(local.get(0));
                    s.onCompleted();
                }                
                else if (local.size() > 1){
                    int first  = rand.nextInt(local.size());
                    int second = (rand.nextInt(local.size()-1) + first + 1) % local.size();
                    
                    s.onNext(func.call(local.get(first), local.get(second)));
                    s.onCompleted();
                }
            }
        });
        
        this.clients = clients;
    }

    @Override
    public void call(List t) {
        this.clients.set(t);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy