package com.networknt.balance;
import com.networknt.registry.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.networknt.utility.Util;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
/**
* Local first load balance give local service high priority than remote services.
* If there is no local service available, then it will adapt round robin strategy.
*
* With all the services in the list of urls, find local services with IP, Chances are
* we have multiple local service, then round robin will be used in this case. If
* there is no local service, find the first remote service according to round robin.
*
* Created by dan on 2016-12-29
*/
public class LocalFirstLoadBalance extends RoundRobinLoadBalance {
static Logger logger = LoggerFactory.getLogger(LocalFirstLoadBalance.class);
static String ip = "0.0.0.0";
static{
// get the address of the localhost
InetAddress inetAddress = Util.getInetAddress();
// get ip address for this host.
ip = inetAddress.getHostAddress();
}
/**
* Local first requestKey is not used as it is ip on the localhost. It first needs to
* find a list of urls on the localhost for the service, and then round robin in the
* list to pick up one.
*
* Currently, this load balance is only used if you deploy the service as standalone
* java process on data center hosts. We need to find a way to identify two VMs or two
* docker containers sitting on the same physical machine in the future to improve it.
*
* It is also suitable if your services are built on top of light-hybrid-4j and want
* to use the remote interface for service to service communication.
*
* @param urls List
* @param requestKey String
* @return URL
*/
@Override
public URL select(List<URL> urls, String requestKey) {
// search for a URL in the same ip first
List<URL> localUrls = searchLocalUrls(urls, ip);
if(localUrls.size() > 0) {
if(localUrls.size() == 1) {
return localUrls.get(0);
} else {
// round robin within localUrls
return doSelect(localUrls);
}
} else {
// round robin within urls
return doSelect(urls);
}
}
private List<URL> searchLocalUrls(List<URL> urls, String ip) {
List<URL> localUrls = new ArrayList<URL>();
long local = ipToLong(ip);
for (URL url : urls) {
long tmp = ipToLong(url.getHost());
if (local != 0 && local == tmp) {
localUrls.add(url);
}
}
return localUrls;
}
public static long ipToLong(final String address) {
final String[] addressBytes = address.split("\\.");
int length = addressBytes.length;
if (length < 3) {
return 0;
}
long ip = 0;
try {
for (int i = 0; i < 4; i++) {
ip <<= 8;
ip |= Integer.parseInt(addressBytes[i]);
}
} catch (Exception e) {
logger.warn("Warn ipToLong address is wrong: address =" + address);
}
return ip;
}
}