Nacos负载均衡策略

news2024/11/26 17:53:10

文章目录

    • 按权重分配流量负载均衡
    • 自定义负载均衡策略

按权重分配流量负载均衡

SpringCloud新版本(2021.x.x)中负载均衡器用LoadBalancer替代了Ribbon,默认只提供了2种负载均衡策略:RandomLoadBalancer 和 RoundRobinLoadBalancer。
SpringCloud Alibaba Nacos 2021.1版本提供了基于Nacos注册中心的轮询策略 NacosLoadBalancer 是基于权重的策略。

  • NacosLoadBalancer的权重策略默认是关闭的。仅识别流量值为0(不引入流量)和非0(引入流量),不支持按照Nacos实例中的流量值进行流量负载均衡。 如果要使用基于权重的负载策略要手动开启。
# 引入依赖loadbalancer依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-loadbalancer</artifactId>
 </dependency>
#开启nacos的负载均衡策略
spring.cloud.loadbalancer.nacos.enabled=true
  • nacos中设置服务对应的权重,就可以生效了。

实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大。

在这里插入图片描述

  • 具体实现,可以查看nacos源码的 NacosLoadBalancer类相关信息。

自定义负载均衡策略

@Configuration
@LoadBalancerClients(defaultConfiguration = {SpringBeanConfiguration.class})
public class SpringBeanConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }


    @Bean
    public ReactorLoadBalancer<ServiceInstance> nacosLoadBalancer(Environment environment,
                                                                  LoadBalancerClientFactory loadBalancerClientFactory,
                                                                  NacosDiscoveryProperties nacosDiscoveryProperties) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new NacosSameClusterWeightedRule(
                loadBalancerClientFactory.getLazyProvider(name,
                        ServiceInstanceListSupplier.class),
                name,nacosDiscoveryProperties);
    }
}
@Slf4j
// 自定义负载均衡实现需要实现 ReactorServiceInstanceLoadBalancer 接口 以及重写choose方法
public class NacosSameClusterWeightedRule implements ReactorServiceInstanceLoadBalancer {

    // 注入当前服务的nacos的配置信息
    private final NacosDiscoveryProperties nacosDiscoveryProperties;

    // loadbalancer 提供的访问当前服务的名称
    final String serviceId;
    
    // loadbalancer 提供的访问的服务列表
    ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

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

/**
     * 服务器调用负载均衡时调的放啊
     * 此处代码内容与 RandomLoadBalancer 一致
     */
    public Mono<Response<ServiceInstance>> choose(Request request) {
        System.out.println("choose.request:"+ request);
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map((serviceInstances) -> this.processInstanceResponse(supplier, serviceInstances));
    }
    
    /**
     * 对负载均衡的服务进行筛选的方法
     * 此处代码内容与 RandomLoadBalancer 一致
     */
    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
        System.out.println("processInstanceResponse.serviceInstances:"+ serviceInstances);
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback)supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }

        return serviceInstanceResponse;
    }

    /**
     * 对负载均衡的服务进行筛选的方法
     * 自定义
     * 此处的 instances 实例列表  只会提供健康的实例  所以不需要担心如果实例无法访问的情况
     */
    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            return new EmptyResponse();
        }
        // 获取当前服务所在的集群名称
        String currentServiceName = nacosDiscoveryProperties.getService();
        System.out.println("currentServiceName:"+currentServiceName);
        // 过滤在同一集群下注册的服务 根据集群名称筛选的集合
        List<ServiceInstance> sameClusterNameInstList  = instances.stream().filter(i-> StringUtils.equals(i.getMetadata().get("nacos.service"),currentServiceName)).collect(Collectors.toList());
        ServiceInstance sameClusterNameInst;
        if (sameClusterNameInstList.isEmpty()) {
            // 如果为空,则根据权重直接过滤所有服务列表
            sameClusterNameInst = getHostByRandomWeight(instances);
        } else {
            // 如果不为空,则根据权重直接过滤所在集群下的服务列表
            sameClusterNameInst = getHostByRandomWeight(sameClusterNameInstList);
        }
        return new DefaultResponse(sameClusterNameInst);
    }

    private ServiceInstance getHostByRandomWeight(List<ServiceInstance> sameClusterNameInstList){

        List<Instance> list = new ArrayList<>();
        Map<String,ServiceInstance> dataMap = new HashMap<>();
        // 此处将 ServiceInstance 转化为 Instance 是为了接下来调用nacos中的权重算法,由于入参不同,所以需要转换,此处建议打断电进行参数调试,以下是我目前为止所用到的参数,转化为map是为了最终方便获取取值到的服务对象
        sameClusterNameInstList.forEach(i->{
            Instance ins = new Instance();
            Map<String, String> metadata = i.getMetadata();

            ins.setInstanceId(metadata.get("nacos.instanceId"));
            ins.setWeight(new BigDecimal(metadata.get("nacos.weight")).doubleValue());
            ins.setClusterName(metadata.get("nacos.cluster"));
            ins.setEphemeral(Boolean.parseBoolean(metadata.get("nacos.ephemeral")));
            ins.setHealthy(Boolean.parseBoolean(metadata.get("nacos.healthy")));
            ins.setPort(i.getPort());
            ins.setIp(i.getHost());
            ins.setServiceName(i.getServiceId());

            ins.setMetadata(metadata);

            list.add(ins);
            // key为服务ID,值为服务对象
            dataMap.put(metadata.get("nacos.instanceId"),i);
        });
        // 调用nacos官方提供的负载均衡权重算法
        System.out.println("main list:{  }" + list);
        Instance hostByRandomWeightCopy = ExtendBalancer.getHostByRandomWeightCopy(list);
        
        // 根据最终ID获取需要返回的实例对象
        return dataMap.get(hostByRandomWeightCopy.getInstanceId());
    }

}

class ExtendBalancer extends Balancer {
    /**
     * 根据自定义规则选择
     */
    public static Instance getHostByRandomWeightCopy(List<Instance> hosts) {

        for (Instance host : hosts) {
            if (host.getServiceName().equals("wms-outbound")) {
                System.out.println("main host:" + host);
                if (host.getPort() == 8906) {
                    continue;
                }
                return host;
            }
        }
        return getHostByRandomWeight(hosts);
    }

}

你知道的越多,你不知道的越多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/643512.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[冷冻电镜]IMOD使用指南

参考教程&#xff1a; Etomo Tuturial for IMOD version 4.11 1. Initial Setup 本教程提供了一个小双轴示例数据集和Etomo的分布指南&#xff0c;更详细的内容参考Tomography Guide。该版本使用1k*1k的图像而不是压缩版本。imodhelp命令可以打开帮助界面&#xff0c;查看各种…

java并发之CAS(Compare and swap)

1. 简介 CAS的底层调用native方法&#xff0c;最终是利用CPU的一个特殊指令&#xff0c;该指令由CPU保证了原子性&#xff0c;而且包含多个操作&#xff0c;比如先比较再更新。 原理&#xff1a; &#xff08;1&#xff09;需要读写的内存值&#xff08;V&#xff09;、原值…

【Kafka】Docker安装kafkajava kafka api

内容目录 一、安装zookeeper1 拉取镜像2 创建network3 启动容器 二、安装kafka1 拉取kafka镜像2 启动kafka容器3 创建topic4 创建生产者5 创建消费者 三、kafka的java api1 producer2 消费者 docker依赖于zookeeper&#xff0c;首先安装zookeeper 一、安装zookeeper 1 拉取镜像…

[PyTorch][chapter 40][数据增强]

前言&#xff1a; 深度学习对数据量要求非常大, 我们通常会遇到图像的数据集比较小,影响Train效果。 这个时候可以通过transformer 方法,增加图像的多样性,达到数据 增强的效果。 transformer 不会单独使用&#xff0c;通常和其它torch 其他类一起使用 transformer 常用方法…

可视管理 数字孪生智慧隧道一体化管控平台

前言 交通是国家发展的关键&#xff0c;四通八达的交通路线&#xff0c;对国家经济、社会等方面的发展起着至关重要的作用。 建设背景 随着社会经济的持续发展与城市化进程的平稳推进&#xff0c;我国公路工程规模逐步扩大&#xff0c;公路工程建设直接影响着城市未来发展与…

Vue 报错 error:0308010C:digital envelope routines::unsupported

症状 Vue 报错error:0308010C:digital envelope routines::unsupported 原因 出现这个错误是因为 node.js V17版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制&#xff0c;可能会对生态系统造成一些影响. 解决方法 方法1 打开终端&#x…

React 应用 Effect Hook 函数式中操作生命周期

React Hook入门小案例 在函数式组件中使用state响应式数据给大家演示了最简单的 Hook操作 那么 我们继续 首先 Hook官方介绍 他没有破坏性是完全可选的 百分比兼容 也就说 我们一起的 类 class的方式也完全可以用 只要 react 16,8以上就可以使用 Hook本身不会影响你的react的理…

ESXi 7.0 U3m Hitachi (日立) 定制版 OEM Custom Installer CD

VMware ESXi 7.0 Update 3m - 领先的裸机 Hypervisor (All OEM Customized Installer CDs) ESXi 7.0 U3m Standard (标准版) ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD ESXi 7.0 U3m HPE (慧与) 定制版 OEM Custom Installer CD ESXi 7.0 U3m Lenovo (联想) 定…

4.单表查询

SQL句子中语法格式提示&#xff1a; 1.中括号&#xff08;[]&#xff09;中的内容为可选项&#xff1b; 2.[&#xff0c;...]表示&#xff0c;前面的内容可重复&#xff1b; 3.大括号&#xff08;{}&#xff09;和竖线&#xff08;|&#xff09;表示选择项&#xff0c;在选择…

chatgpt赋能python:Python怎么导入第三方库

Python怎么导入第三方库 如果你是Python开发者&#xff0c;你一定会使用各种第三方库来加速你的开发过程。这些库可能是Python标准库之外的代码&#xff0c;或由其他人编写的自定义代码。使用这些库可以让你的开发更高效、更易于管理&#xff0c;并且可以避免重复造轮子。 但…

RabbitMQ虚拟主机无法启动的原因和解决方案

RabbitMQ虚拟主机无法启动的原因和解决方案 摘要&#xff1a; RabbitMQ是一个广泛使用的开源消息代理系统&#xff0c;但在使用过程中可能会遇到虚拟主机无法启动的问题。本文将探讨可能导致该问题的原因&#xff0c;并提供相应的解决方案&#xff0c;以帮助读者解决RabbitMQ虚…

Learning C++ No.31 【线程库实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/11/14:40&#xff0c;实训课中&#xff0c;实训场地有空调&#xff0c;除了凳子坐着不舒服之外&#xff0c;其它条件都挺好&#xff0c;主要是我带上了我自己的小键盘&#xff0c;并且教室可以充电&#xff0c;哈哈哈&#xff0c…

在做自动化测试之前你需要知道的

B站视频教程&#xff1a;Python自动化测试&#xff1a;7天练完这60个实战项目&#xff0c;年薪过35w。 什么是自动化测试&#xff1f; 做测试好几年了&#xff0c;真正学习和实践自动化测试一年&#xff0c;自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践…

信息系统管理工程师-学习笔记1-信息化知识

考点1 信息与信息系统 信息的概念 信息的定义: 是有别与物质与能量的第三种东西,是对事物运动状态或存在方式的不确定行的描述 信息是按特定方式组织在一起的客体属性的集合,具有超出这些客体属性本身之外的价值两层次 1.本体论层次 : 纯客观的层次,只与客体本身的因素有关,与主…

python cv2的一些操作,如膨胀,画线,滤波等

目录 0. cv2简介1. 打开摄像头2. 画图,画线3. 滤波4. 获取角点5. 梯度边缘6. 图形匹配7. 形态学变化-膨胀腐蚀8. 二值化阈值10. 总结 0. cv2简介 在这里先简单介绍一下cv2吧。 cv2 是 OpenCV Python 库的主要模块&#xff0c;提供了许多图像处理和计算机视觉方面的函数和工具。…

vue2组件通信

父传子 传递静态或动态 Prop <!-- 传入静态值 --> <blog-post title"hai hai hai"></blog-post><!-- 传入变量值 --> <blog-post :title"info.title"></blog-post>传入一个对象的所有 property 数据 post: {id: 1…

进程管道:popen函数实例

基础知识 可能最简单的在两个程序之间传递数据的方法就是使用popen和pclose函数了。它们的原型如下所示&#xff1a; #include <stdio.h>FILE *popen(const char *command, const char *type);int pclose(FILE *stream); 1&#xff0e;popen函数 popen函数允许一个程…

因为Json,controller方法单参数 导致脑袋短路

对于单参数方法&#xff0c; 一直喜欢用parameter方式。今天不知道为啥&#xff0c;就想用Json方式&#xff0c;然后无法直接传递。各种自我怀疑&#xff0c;然后尝试。 突然醒悟过来&#xff0c;Json方式是key/value模式&#xff0c;单参数String类型&#xff0c;没有key。必…

TreeMap源码

介绍 如果我们希望Map可以保持key的大小顺序时&#xff0c;就需要利用TreeMap。底层使用了红黑树&#xff0c;左子树总小于root&#xff0c;右子树总大于root&#xff0c;具有很好的平衡性,操作速度达到log(n)。 TreeMap 相比于HashMap多实现了了NavigableMap接口&#xff08…

5. SpringCloudAlibab 集成 gateway

一、什么是 Spring Cloud Gateway 1、网关简介 网关作为流量的入口&#xff0c;常用的功能包括路由转发&#xff0c;权限校验&#xff0c;限流等等。 SpringCloud Gateway是 Spring Cloud 官方推出的第二代网关框架&#xff0c;定位取代 Netflix Zuul。相对Zuul来说&#xf…