手写SpringCloud系列-负载均衡算法实现

手写SpringCLoud项目地址,求个star
github:https://github.com/huangjianguo2000/spring-cloud-lightweight
gitee:https://gitee.com/huangjianguo2000/spring-cloud-lightweigh

一:什么是负载均衡

最开始的系统访问量很少,就一个单机就足够,随着系统越来越大,访问量越来越大,系统逐渐变为微服务架构体系,同一个功能需要多台服务器同时提供服务,这个时候我们的请求具体落在哪台服务器就成了一个需要思考的问题,如何使资源合理分配就是负载均衡要解决的问题
手写SpringCloud系列-负载均衡算法实现_第1张图片
常见的负载均衡算法包括轮询(Round Robin)、加权轮询、最少连接(Least Connections)、最短响应时间,固定IP访问等等。

  1. 轮询(Round Robin): 这是一种最简单的负载均衡算法,请求按顺序依次分配到每个服务器。每个请求都会被依次发送到不同的服务器,然后从头开始。这种算法适用于服务器性能相对均衡的情况。
  2. 加权轮询(Weighted Round Robin): 这是轮询算法的一种变体,服务器可以设置不同的权重,权重越高的服务器会获得更多的请求。这样可以根据服务器的性能来分配负载,提高性能更高的服务器的工作负荷。
  3. 最少连接(Least Connections): 这种算法会将请求发送到当前连接数最少的服务器上。这意味着负载均衡器会优先将请求分配给负载较轻的服务器,以实现更均衡的负载。
  4. 最短响应时间(Least Response Time): 在这种算法中,负载均衡器会选择具有最短响应时间的服务器来处理请求。这可以确保请求被尽快处理,从而提高用户体验。
  5. 随机(Random): 这是一种随机分配请求的算法,每个请求被随机发送到一个服务器上。尽管随机算法相对简单,但无法确保负载均衡的效果。
  6. IP 哈希(IP Hash): 这种算法基于客户端的 IP 地址,将同一客户端的请求始终分配给同一台服务器。这对于需要保持会话一致性的应用很有用。

二:轮询负载均衡算法实现

轮询很简单,我们记录当前请求下标,下一次请求的时候就请求下标加1位置的服务实例即可。

1.定义一个接口

public interface LoadBalancer{
    /**
     * 获取远程服务的IP地址和端口的完整地址 http://xxx:port
     * @param serviceName 服务名称
     * @return
     */
    String getPath(String serviceName);
}

2.定义一个抽象类,实现getPath方法,同时定义模板方法。


/**
 * 定义模板方法
 */
public  abstract class AbstractLoadBalancer implements LoadBalancer{

    private static final Logger logger = LoggerFactory.getLogger(AbstractLoadBalancer.class);

    @Override
    public String getPath(String serviceName) {
        List<ServiceInstance> instances = getInstances(serviceName);

        if (instances.isEmpty()) {
            LoggerUtils.printIfErrorEnabled(logger,"No instances available");
            return null;
        }
        ServiceInstance instance = selectInstance(serviceName, instances);

        return "http://" + instance.getHost() + ":" + instance.getPort();
    }

    /**
     * 根据服务名称获取实例
     */
    protected abstract List<ServiceInstance> getInstances(String serviceName);

    /**
     * 选择实例
     */
    protected abstract ServiceInstance selectInstance(String serviceName,List<ServiceInstance> instances);
}

3.实现基于轮询的负载均衡算法

/**
 * 基于轮询的负载均衡器
 */
public class DefaultLoadBalancer extends AbstractLoadBalancer{

    /**
     * Spring context
     */
    private DiscoveryClient discoveryClient;

    /**
     * 记录轮询下标
     */
    private Map<String, AtomicInteger> selectMap;

    /**
     * 拿到服务发现客户端
     */
    public DefaultLoadBalancer(ApplicationContext applicationContext){
        this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
        selectMap = new ConcurrentHashMap<>();
    }

    /**
     * 获取服务名称对应的所有实例
     * @param serviceName
     * @return
     */
    @Override
    protected List<ServiceInstance> getInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }

    /**
     * 选择一个实例
     */
    @Override
    protected ServiceInstance selectInstance(String serviceName, List<ServiceInstance> instances) {
        AtomicInteger atomicInteger = selectMap.get(serviceName);
        if(atomicInteger == null){
            atomicInteger = new AtomicInteger(0);
        }
        // index++
        atomicInteger.incrementAndGet();
        if(atomicInteger.get() >= instances.size()){
            atomicInteger.compareAndSet(atomicInteger.get(), 0);
        }
        selectMap.put(serviceName, atomicInteger);
        return instances.get(atomicInteger.get() % instances.size());
    }

}

你可能感兴趣的:(手写SpringCloud,spring,cloud,负载均衡,算法)