文章 62
浏览 15135
自研网关06 -实现负载均衡策略

自研网关06 -实现负载均衡策略

nacos 注册中心一个服务,会存在多个实例,这时候网关就不是很清楚最终需要向那个实例节点发送请求,所以需要一个负载均衡测试算法

通过工厂 + 策略模式

当网关执行请求的时候,从自己的注册器,本地缓存获取到了 nacos 的服务元数据信息,一个服务存在多个节点的时候,根据客户端 SDK 服务自己配置的策略方式,进行均衡


        BalanceType balanceType = BalanceType.valueOf(serviceDefinition.getRobinType());
        Set<ServiceInstance> serviceInstances = instance.getServiceInstanceByUniqueId(gateWayRequest.getUniqueId(), false);

        ServiceInstance serviceInstance = BalanceManger.getInstance().getIBalance(balanceType, new ArrayList<>(serviceInstances)).select();

        gatewayContext.getRequest().setModifyHost(serviceInstance.getIp() + ":" + serviceInstance.getPort());
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiService {
    String serviceId();

    String version() default "1.0";

    ApiProtocol protocol();

    String patternPath();

    BalanceType robinType() default BalanceType.RANDOM;
}
  • 随机均衡
package com.xiaohu.core.loadbalance;

import java.util.List;
import java.util.Random;

/**
 * @Version 1.0
 * @Author huqiang 随机负载均衡
 * @Description RandomRobin
 * @Date 2024/4/28 下午1:25
 **/
public class RandomRobin<T> implements IBalance<T>{
    private List<T> elements;

    private final Random random ;

    public RandomRobin(List<T> elements) {
        random = new Random();
        init(elements);
    }

    @Override
    public void init(List<T> elements) {
      this.elements = elements;
    }

    @Override
    public T select() {
        if (elements == null || elements.isEmpty()) {
            throw new IllegalStateException("Cannot select an element from an empty list");
        }
        // 使用Random.nextInt(int n) 来生成一个介于0(包含)和指定值n(不包含)之间的随机数
        int randomIndex = random.nextInt(elements.size());
        return elements.get(randomIndex);
    }
}
  • 轮询均衡
package com.xiaohu.core.loadbalance;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Version 1.0
 * @Author huqiang 轮询负载均衡
 * @Description RandomRobin
 * @Date 2024/4/28 下午1:25
 **/
public class RoundRobin<T> implements IBalance<T> {

    private List<T> elements;
    private AtomicInteger index;

    public RoundRobin(List<T> elements) {
        init(elements);
    }

    @Override
    public void init(List<T> elements) {
        this.elements = elements;
        this.index = new AtomicInteger(0);
    }

    @Override
    public T select() {
        if (elements == null || elements.isEmpty()) {
            throw new IllegalStateException("Cannot select an element from an empty list");
        }

        int currentIndex = index.getAndUpdate(i -> (i + 1) % elements.size());
        return elements.get(currentIndex);
    }
}
  • 权重均衡
package com.xiaohu.core.loadbalance;

import com.xiaohu.common.config.ServiceInstance;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;

/**
 * @Version 1.0
 * @Author huqiang
 * @Description WeightedRandom 权重算法
 * @Date 2024/4/28 下午12:50
 **/
public class WeightedRandomRobin<T> implements IBalance<T> {

    private class WeightedElement {
        double accumulatedWeight;
        T object;

        public WeightedElement(T object, double accumulatedWeight) {
            this.object = object;
            this.accumulatedWeight = accumulatedWeight;
        }
    }

    private List<WeightedElement> weightedElements;
    private final List<Double> weights = new LinkedList<>();
    private double totalWeight;
    private Random random;

    @SuppressWarnings("unchecked")
    public WeightedRandomRobin(List<T> elements,List<Double>...weights) {

        T t = elements.get(0);
        if (t instanceof ServiceInstance serviceInstance) {
            for (int i = 0; i < elements.size(); i++) {
                this.weights.add(Double.valueOf(serviceInstance.getWeight()));
            }
        }else {
            this.weights.addAll(weights[0]);
        }

        if (CollectionUtils.isEmpty(elements) || elements.size() != this.weights.size()) {
            throw new IllegalArgumentException("Elements and weights must be the same size");
        }

        init(elements);
    }

    @Override
    public void init(List<T> elements) {
        this.weightedElements = new ArrayList<>(elements.size());
        double accumulatedWeight = 0.0;

        for (int i = 0; i < elements.size(); i++) {
            accumulatedWeight += weights.get(i);
            weightedElements.add(new WeightedElement(elements.get(i), accumulatedWeight));
        }

        this.totalWeight = accumulatedWeight;
        this.random = new Random();
    }

    @Override
    public T select() {
        double randomWeight = random.nextDouble() * totalWeight;
        for (WeightedElement we : weightedElements) {
            if (randomWeight <= we.accumulatedWeight) {
                return we.object;
            }
        }
        //找不到取第一个
        return weightedElements.get(0).object;
    }
}
  • 随机权重均衡
package com.xiaohu.core.loadbalance;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author xiaohugg 随机+轮询算法
 * @version 1.0
 * @date 2024/4/25 22:10:25
 */
public class RandomRoundRobin<T> implements IBalance<T> {

    private List<T> elements;
    private List<Integer> indexPool;

    public RandomRoundRobin(List<T> elements) {
       init(elements);
    }

    @Override
    public void init(List<T> elements) {
        this.elements = new ArrayList<>(elements);
        this.indexPool = new ArrayList<>(elements.size());
        for (int i = 0; i < elements.size(); i++) {
            this.indexPool.add(i);
        }
    }

    @Override
    public T select() {
        if (indexPool.isEmpty()) {
            for (int i = 0; i < elements.size(); i++) {
                indexPool.add(i);
            }
        }
        Collections.shuffle(indexPool);
        Integer index = indexPool.remove(indexPool.size() - 1);
        return elements.get(index);
    }
}

负载均衡管理器类

package com.xiaohu.core.loadbalance;

import com.xiaohu.common.enums.BalanceType;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * @Version 1.0
 * @Author huqiang
 * @Description BalanceManger
 * @Date 2024/4/28 下午1:02
 **/
public class BalanceManger {
    private static final BalanceManger INSTANCE = new BalanceManger();

    private final Map<String, Map<BalanceType, IBalance<?>>> balanceMapCache = new ConcurrentHashMap<>();

    private BalanceManger() {}

    public <T> IBalance<T> getIBalance(BalanceType type, List<T> elements, String serviceId) {
        Map<BalanceType, IBalance<?>> serviceBalances = balanceMapCache.computeIfAbsent(serviceId, k -> new ConcurrentHashMap<>());
        synchronized (serviceBalances) {
            @SuppressWarnings("unchecked")
            IBalance<T> balance = (IBalance<T>) serviceBalances.computeIfAbsent(type, t -> createBalance(type, elements));
            return balance;
        }
    }

    private <T> IBalance<T> createBalance(BalanceType type, List<T> elements) {
        Map<BalanceType, Function<List<T>, IBalance<T>>> balanceMap = getBalanceMap();
        Function<List<T>, IBalance<T>> selector = balanceMap.get(type);
        if (selector == null) {
            throw new IllegalArgumentException("Unsupported balance type: " + type);
        }
        return selector.apply(elements);
    }

    @SuppressWarnings("unchecked")
    private <T> Map<BalanceType, Function<List<T>, IBalance<T>>> getBalanceMap() {
        return Map.of(
                BalanceType.RANDOM, RandomRobin::new,
                BalanceType.WEIGHT, WeightedRandomRobin::new,
                BalanceType.RANDOM_ROUND, RandomRoundRobin::new,
                BalanceType.ROUND, RoundRobin::new
        );
    }
    public static BalanceManger getInstance() {
        return INSTANCE;
    }
}

标题:自研网关06 -实现负载均衡策略
作者:xiaohugg
地址:https://xiaohugg.top/articles/2024/04/28/1714287945654.html

人民有信仰 民族有希望 国家有力量