一 起因
因为最近在做一个中间件的服务,服务下游有许多服务,需要实现单机对下游服务负载均衡机制,分享下几种简单负载均衡算法的java实现。具体负载均衡原理此处不再详细介绍。 目前通过注册中心sdk获取下游服务的实例列表。在调用下游前通过算法计算请求下游的服务具体那个实例。
二 负载均衡算法
1 轮询算法
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 轮询算法
*/
public class RoundRobin {
///按微服务编码定义全局计数器,每次调用累加
private static Map<String, AtomicInteger> instanceCounts = new ConcurrentHashMap<>();
/**
* 获取实例信息
* @param microServiceCode 微服务编码
* @param addressList 实例列表
* @return
*/
public static String roundRobin(String microServiceCode, List<String> addressList) {
if (!instanceCounts.containsKey(microServiceCode)) {
instanceCounts.put(microServiceCode, new AtomicInteger(0));
}
int instanceCount = addressList.size();
AtomicInteger atomicInteger = instanceCounts.get(microServiceCode);
return addressList.get(getIndex(instanceCount, atomicInteger) % instanceCount);
}
/**
* 计算轮询的下标
* @param instanceCount 微服务编码下实例总数
* @param atomicInteger 该微服务编码对应的原子类计数器
* @return
*/
public static int getIndex(int instanceCount, AtomicInteger atomicInteger) {
if (atomicInteger == null || instanceCount == 0) {
return 0;
}
if (atomicInteger.get() == instanceCount) {
atomicInteger.getAndSet(0);
}
return atomicInteger.getAndIncrement() % instanceCount;
}
}
2 加权轮询
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 加权轮询
*/
public class WeightRoundRobin {
//按微服务编码定义全局计数器,每次调用累加
private static Map<String, AtomicInteger> instanceCounts = new ConcurrentHashMap<>();
//微服务编码对应的权重总和
private static Map<String, Integer> instanceWeightCounts = new ConcurrentHashMap<>();
/**
*
* @param microServiceCode 微服务编码
* @param addressList 实例信息列表
* @param weightMap 权重信息
* @return
*/
public synchronized String WeightRoundRobin(String microServiceCode, List<String> addressList, Map<String, Integer> weightMap) {
int weightSum;
AtomicInteger atomicInteger;
if (!instanceWeightCounts.containsKey(microServiceCode) || !instanceCounts.containsKey(microServiceCode)) {
weightSum = weightMap.values().stream().reduce(Integer::sum).orElse(0);
instanceWeightCounts.put(microServiceCode, weightSum);
atomicInteger = new AtomicInteger(0);
instanceCounts.put(microServiceCode, atomicInteger);
} else {
weightSum = instanceWeightCounts.get(microServiceCode);
atomicInteger = instanceCounts.get(microServiceCode);
}
int currentIndex = atomicInteger.incrementAndGet() % weightSum;
for (Map.Entry<String, Integer> entry : weightMap.entrySet()) {
String serverAddress = entry.getKey();
Integer weight = entry.getValue();
currentIndex -= weight;
if (currentIndex < 0) {
return serverAddress;
}
}
return null;
}
}
3 随机数
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;
/**
* 随机数算法
*/
public class Random {
public static String random(String microServiceCode, List<String> addressList){
int instanceCount = addressList.size();
//生成一个随机数
int randomIndex = new SecureRandom().nextInt(instanceCount);
return addressList.get(randomIndex);
}
}
4.最短响应时间算法
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* 最小响应时间负载均衡算法
*/
public class ShortestResponseLoadBalance {
//按微服务编码记录该微服务下对应的所有实例以及其响应时间
private Map<String, Map<String, AtomicInteger>> responseTimes = new ConcurrentHashMap<>();
public void addServer(String microServiceCode, Map<String, AtomicInteger> instances) {
responseTimes.put(microServiceCode, instances);
}
public String getBestServer(String microServiceCode, List<String> addressList) {
String res = null;
int minResponseTime = Integer.MAX_VALUE;
Map<String, AtomicInteger> bestInstance = responseTimes.get(microServiceCode);
for (String instance : addressList) {
int responseTime = bestInstance.get(instance).get();
if (responseTime < minResponseTime) {
minResponseTime = responseTime;
res = instance;
}
}
return res;
}
public void updateResponseTime(String microServiceCode, String instance, int responseTime) {
responseTimes.get(microServiceCode).putIfAbsent(instance, new AtomicInteger(responseTime));
}
}