几种简单负载均衡算法java实现

126 阅读2分钟

一 起因

因为最近在做一个中间件的服务,服务下游有许多服务,需要实现单机对下游服务负载均衡机制,分享下几种简单负载均衡算法的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));
    }

}