自定义nacos负载均衡

目录

1.前言
2.代码
3.nacos配置
4.测试
5.源码跟踪
6.多服务节点配置

1. 前言

之前新增临时服务器,发现直接在nacos中配置负载均衡未生效,纠结了一阵未解决
本着先快速地解决问题,再优雅地解决问题的原则,先在临时服务器(同一台服务器)多部署了两个服务,以这种LOW逼的方式变向地实现了负载均衡(让高配的服务器权重提高,因为同一台服务器部署了多个服务)

现在有时间了,回过头看了看nacos的自定义负载均衡,然后整理了一下

2. 代码

在API网关中添加如下代码,实现 alibaba gateway 到服务节点的 ribbon 负载均衡

2.1、自定义负载均衡规则、重写choose方法

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 支持Nacos权重配置的负载均衡策略
 *
 * @author weiheng
 * @date 2021-12-20 16:30:56
 **/
@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {

	@Autowired
	private NacosDiscoveryProperties nacosDiscoveryProperties;

	@Autowired
	private NacosServiceManager nacosServiceManager;

	/**
	 * 读取配置文件,并初始化NacosWeightedRule
	 *
	 * @param iClientConfig iClientConfig
	 */
	@Override
	public void initWithNiwsConfig(IClientConfig iClientConfig) {
		// do nothing
	}

	@Override
	public Server choose(Object key) {
		BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();

		// 需要请求的微服务名称
		String name = loadBalancer.getName();
		// 获取服务发现的相关API
		NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());

		try {
			// 调用该方法时nacos client会自动通过基于权重的负载均衡算法选取一个实例
			Instance instance = namingService.selectOneHealthyInstance(name);
			log.info("=============invoke serviceName:{}, ip:{}, port:{}", instance.getServiceName(), instance.getIp(), instance.getPort());
			return new NacosServer(instance);
		} catch (NacosException e) {
			return null;
		}
	}

}

2.2、将Rule规则提交给spring容器

import com.applet.gateway.config.NacosWeightedRule;
import com.netflix.loadbalancer.IRule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;

/**
 * 网关启动程序
 * @author weiheng
 */
@Slf4j
@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class AppletGatewayApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(AppletGatewayApplication.class, args);
        System.out.println("API网关启动成功");
    }

    /**
     * <pre>
     * 自定义nacos负载均衡策略
     * <pre>
     * @date 2021/12/21 9:58
     * @author wei.heng
     */
    @Bean
	public IRule getRule() {
		return new NacosWeightedRule();
	}
}

3. nacos权重配置

这里本地测试,咱随便改几个值了
在这里插入图片描述

4. 测试

使用psotman连续请求 10 次后台接口
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到,按权重分配,后台服务拿到的请求

服务权重请求次数
95000.11
95010.26
95030.73

为什么权重高的服务,接收的请求反而少呢?
为什么请求次数不是1:2:7呢?

5.源码跟踪

针对测试结果得到的疑惑,我们跟着源码走一走
在这里插入图片描述
在这里插入图片描述
源码的核心代码
com.alibaba.nacos.client.naming.utils.Chooser

    /**
     * Random get one item with weight.
     *
     * @return item
     */
    public T randomWithWeight() {
        Ref<T> ref = this.ref;
        // 取0到1之间的随机double值
        double random = ThreadLocalRandom.current().nextDouble(0, 1);
        // 通过二分查找后台执行 index = -index - 1,拿到节点的数据下标
        // 注意,这里权重值都是配置的0到1之间的double值
        int index = Arrays.binarySearch(ref.weights, random);
        if (index < 0) {
            index = -index - 1;
        } else {
            return ref.items.get(index);
        }
        
        if (index >= 0 && index < ref.weights.length) {
            if (random < ref.weights[index]) {
                return ref.items.get(index);
            }
        }
        
        /* This should never happen, but it ensures we will return a correct
         * object in case there is some floating point inequality problem
         * wrt the cumulative probabilities. */
        return ref.items.get(ref.items.size() - 1);
    }

好了,通过上面这段代码,可以看出,这里取的随机数,前面的测试结果应该是正常的
索性又测了一把,这次把请求的次数拉大(做了几十次请求),然后发现确实是按1:2:7得到的服务分发
在次数很少的时候,比如10以内,可能会出现权重低的服务得到请求更多(这个是正常的,因为是随机数获取权重嘛)

6.多服务节点配置

当一个服务节点,需要同时路由到多个服务节点的时候,前面的配置就会抛异常
可以稍微改一下,为各服务节点做独立的 ribbon 配置

6.1 自定义负载均衡规则

import com.netflix.loadbalancer.IRule;
import com.ruoyi.gateway.config.NacosWeightedRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <pre>
 * 自定义Nacos负载均衡策略
 * <pre>
 * @date 2021/12/24 11:34
 * @author wei.heng
 */
@Configuration
public class DefaultRibbonConfiguration {

	@Bean
	public IRule getRule() {
		return new NacosWeightedRule();
	}
}

6.2 为各个服务单独配置负载均衡

6.2.1 方法1 - 代码配置

import com.deao.common.core.constant.ServiceNameConstants;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;

/**
 * @date 2021/12/24 11:38
 * @author wei.heng
 */
@Configuration
@RibbonClient(name = ServiceNameConstants.GAS_MSGCENTER ,configuration = DefaultRibbonConfiguration.class)
public class MsgCenterRibbonConfig {
}
import com.deao.common.core.constant.ServiceNameConstants;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;

/**
 * @date 2021/12/24 11:38
 * @author wei.heng
 */
@Configuration
@RibbonClient(name = ServiceNameConstants.FLOW_SERVICE ,configuration = DefaultRibbonConfiguration.class)
public class FlowRibbonConfig {
}

6.2.2 方法2 - 直接在nacos的yml文件中,对具体服务节点进行ribbon负载策略配置

格式:

[节点名称]:
	ribbon:
		NFLoadBalancerRuleClassName: 

示例:

app-teacher-user:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
app-quality-credit:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

到这里差不多可以投入生产使用了
不过感觉在nacos中配置权重,用起来也不是很方便
这里改成 WeightedResponseTimeRule 先用一段时间试试了
看起来这个更靠谱

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值