SpringCloud之LoadBalancer自定义负载均衡算法,基于nacos权重

简介: ReactorLoadBalancer接口,实现自定义负载算法需要实现该接口,并实现choose逻辑,选取对应的节点。

ReactorLoadBalancer接口,实现自定义负载算法需要实现该接口,并实现choose逻辑,选取对应的节点


public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {
    Mono<Response<T>> choose(Request request);

    default Mono<Response<T>> choose() {
        return this.choose(REQUEST);
    }
}

RoundRobin算法核心源码

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serviceId);
            }

            return new EmptyResponse();
        } else {
            //通过cas的position变量自增,循环 % 实例数。
            int pos = Math.abs(this.position.incrementAndGet());
            ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
            return new DefaultResponse(instance);
        }
    }

nacos权重


nacos可以配置不同实例的权重信息,可以在


  1. yaml中配置spirng.cloud.nacos.discovery.weight 数值范围从1-100 ,默认为1
  2. 可以在nacos面板找到该实例信息,并实时配置实例的权重




基于nacos权重实现自定义负载


权重:数值越高,代表被选取的概率越大.

根据RoundRobin源码,自定义NacosWeightLoadBalancer

package cn.axj.loadbalancer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.*;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 基于nacos权重的负载均衡
*/
public class NacosWeightLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private static final Log log = LogFactory.getLog(NacosWeightLoadBalancer.class);
    private final String serviceId;
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    //nacos权重获取名称,在nacos元数据中
    private static final String NACOS_WEIGHT_NAME = "nacos.weight";

    public NacosWeightLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map((serviceInstances) -> {
            return this.processInstanceResponse(supplier, serviceInstances);
        });
    }


    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback)supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }

        return serviceInstanceResponse;
    }


    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serviceId);
            }
        } else {
            //根据权重选择实例,权重高的被选中的概率大
            //nacos.weight的值越大,被选中的概率越大
            Double totalWeight = 0D;
            for (ServiceInstance instance : instances) {
                String s = instance.getMetadata().get(NACOS_WEIGHT_NAME);
                double weight = Double.parseDouble(s);
                totalWeight = totalWeight + weight;
                //放置当前实例的权重区间
                instance.getMetadata().put("weight",String.valueOf(totalWeight));
            }
            //随机获取一个区间类的数值,nacos权重越大,区间越大,则随机数值落到相应的区间的概率是由区间的大小来决定的。
            double index = ThreadLocalRandom.current().nextDouble(totalWeight);
            //根据权重区间选择实例
            for (ServiceInstance instance : instances) {
                double weight = Double.parseDouble(instance.getMetadata().get("weight"));
                if (index <= weight) {
                    return new DefaultResponse(instance);
                }
            }

        }
        return new EmptyResponse();
    }
}

配置使用


增加WeightLoadBalanceConfiguration

public class WeightLoadBalanceConfiguration {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> weightLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new NacosWeightLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

修改主类配置

@LoadBalancerClients({
        @LoadBalancerClient(name = "loadbalance-provider-service", configuration = WeightLoadBalanceConfiguration.class)
})

目录
相关文章
|
19天前
|
缓存 负载均衡 Java
Java一分钟之-Spring Cloud Netflix Ribbon:客户端负载均衡
【6月更文挑战第9天】Spring Cloud Netflix Ribbon是客户端负载均衡器,用于服务间的智能路由。本文介绍了Ribbon的基本概念、快速入门步骤,包括添加依赖、配置服务调用和使用RestTemplate。此外,还讨论了常见问题,如服务实例选择不均、超时和重试设置不当、服务列表更新不及时,并提供了相应的解决策略。最后,展示了如何自定义负载均衡策略。理解并正确使用Ribbon能提升微服务架构的稳定性和效率。
81 3
|
3天前
|
Java Nacos Spring
SpringCloud之LoadBalancer负载均衡器的简单使用
RoundRobin: 轮询策略,意思循环往复的的服务进行选取。
12 0
|
1月前
|
监控 Nacos Docker
【开发问题记录】Nacos修改服务实例权重时报错
【开发问题记录】Nacos修改服务实例权重时报错
50 1
|
1月前
|
负载均衡
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
27 0
|
1月前
|
负载均衡 算法 应用服务中间件
面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
68 0
|
1月前
|
负载均衡 应用服务中间件 API
Nginx配置文件详解Nginx负载均衡Nginx静态配置Nginx反向代理
Nginx配置文件详解Nginx负载均衡Nginx静态配置Nginx反向代理
67 4
|
14天前
|
缓存 负载均衡 算法
解读 Nginx:构建高效反向代理和负载均衡的秘密
解读 Nginx:构建高效反向代理和负载均衡的秘密
25 2
|
1月前
|
负载均衡 应用服务中间件 nginx
解决nginx配置负载均衡时invalid host in upstream报错
在Windows环境下,配置Nginx 1.11.5进行负载均衡时遇到问题,服务无法启动。错误日志显示“invalid host in upstream”。检查发现上游服务器列表中,192.168.29.128的主机地址无效。负载均衡配置中,两个服务器地址前误加了&quot;http://&quot;。修正方法是删除上游服务器列表和proxy_pass中的&quot;http://&quot;。问题解决后,Nginx服务应能正常启动。
108 4
解决nginx配置负载均衡时invalid host in upstream报错
|
1天前
|
负载均衡 应用服务中间件 开发工具
技术笔记:nginx和keeplive实现负载均衡高可用
技术笔记:nginx和keeplive实现负载均衡高可用
|
1月前
|
负载均衡 前端开发 应用服务中间件
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400