当前位置: 首页 > news >正文

【Nacos无压力源码领读】(二) 集成 LoadBanlancer 与 OpenFeign

上一篇文章中, 详细介绍了 Nacos 注册中心的原理, 相信看完后, 大家应该完全掌握了 Nacos 客户端是如何自动进行服务注册的, 以及 Nacos 客户端是如何订阅服务实例信息的, 以及 Nacos 服务器是如何处理客户端的注册和订阅请求的;

本文承上启下, 在订阅服务实例的基础上, 介绍如何在实例之间进行选择, 实现负载均衡; 并详细介绍了负载均衡组件 LocaBanlancer 和函数式调用组件 OpenFeign 是如何与 Nacos 注册中心进行集成的;

如果在阅读过程中对文中提到的 SpringBoot 启动过程以及扩展机制不太了解, 或者对 @Import 注解不了解, 参考这篇文章 SpringBoot启动流程与配置类处理机制详解, 附源码与思维导图, 强烈建议学习后再来读本文;

LoadBalancer

  1. Nacos 1.X 版本自动引入 Ribbon 依赖, 使用 Ribbon 做负载均衡;

  2. Nacos 2.X 版本就没有了, 因为 Ribbon 的特性已经不满足 SpringBoot 的要求;

  3. 2.X 版本可以用 SpringCloud 团队提供的 LoadBalancer 组件来做负载均衡;

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

LoadBalancerClient

Spring Cloud LoadBalancer :: Spring Cloud Commons

  1. SpringCloud 定义的接口, 用于负载均衡地选择服务实例, 是SpringCloud制定的负载均衡规范;

  2. 由具体厂商去实现这个接口, 比如 Ribbon 和 LoadBanlancer 都提供了实现类;

    例如 LoadBalancer 包下 spring.factories 指定了自动配置类BlockingLoadBalancerClientAutoConfiguration;

    这个配置类向 Spring 容器注册了一个 BlockingLoadBalancerClient bean;

    这样就可以使用 @Autowired 注解获取 LoadBalancerClient并使用;

  3. 两个关键方法, chooseexecute

    choose 方法底层实现本质上仍然是调用了NamingService ( 使用 Nacos 时自然就是NacosNamingService )的 selectInstances 方法, 订阅服务并获取所有实例, 然后根据负载均衡算法选择一个实例返回;

  4. execute 方法有两个重载, 一个需要传入具体的 ServiceInstance, 一个不需要;

    调用不传 Instance 的 execute 方法时, 底层实现会先调用 choose 方法选出一个实例, 然后调用有 Instance 参数的 execute 方法完成请求发送;

  5. LoadBalancerClient 使用, 可以通过直接注入 LoadBanlancerClient对象来使用

@RequestMapping("/order/*")
public class OrderController {@AutowiredLoadBalancerClient loadBalancerClient;@AutowiredRestTemplate restTemplate;@GetMapping("loadbalancer")public String test0(){ServiceInstance instance = loadBalancerClient.choose("stock-service");String url = instance.getUri() + "/stock/test0";return restTemplate.getForObject(url, String.class);}
}
  1. 或者使用@LoadBalanced注解, 注册有复杂均衡功能的 RestTemplate
@Bean
@LoadBalanced
public RestTemplate restTemplate(){return new RestTemplate();
}@GetMapping("loadbalanced")
public String test1(){return restTemplate.getForObject("http://stock-service/stock/test0", String.class);
}

RestTemplate 持有一个 ClientHttpRequestInterceptor的链表; RestTemplate 发送请求之前会先调用这些 Interceptor 的拦截方法;

在 LoadBalancer 的自动配置类中, 会注入所有有@LoadBalanced注解修饰的 RestTemplate bean, 并且会将一个LoadBalancerInterceptor对象放到这些 RestTemplate 对象的拦截器列表中;

这个拦截器会拦截 RestTemplate 发送的请求, 调用LoadBalancerClient不带 ServiceInstance 参数的 execute 方法发送请求; 实现负载均衡;

负载均衡策略

默认的是轮询策略RoundRobinLoadBalancer; 也可以选择RandomLoadBalancer, 这俩都是 SpringCloud 提供的;

@LoadBalancerClients({@LoadBalancerClient(name = "order-service", configuration = RandomLoadBalancerConfig.class),@LoadBalancerClient(name = "stock-service", configuration = RandomLoadBalancerConfig.class)
})// 对所有服务有效
@LoadBalancerClients(defaultConfiguration = RandomLoadBalancerConfig.class)
public class RandomLoadBalancerConfig {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}

OpenFeign

@FeignClient("course-service")
public interface CourseFeignClient {@GetMapping("/feign/course")String course();
}@FeignClient("student-service")
public interface CourseFeignClient {@GetMapping("/feign/stu")String course();
}
@EnableFeignClients
public class OrderApp {public static void main(String[] args) {SpringApplication.run(OrderApp.class, args);}
}
  1. @EnableFeignClients 注解通过 @Import注解引入了一个ImportBeanDefinitionRegistrar; 其注册方法如下:

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {// .....一些不重要的代码this.registerDefaultConfiguration(metadata, registry);this.registerFeignClients(metadata, registry);
    }
    

registerFeignClients

  1. 拿到 @EnableFeignClients 注解的属性;

  2. 创建一个空 Set, 保存 BeanDefinition;

  3. 看你的 @EnableFeignClients 注解的 clients 属性是否为空, 如果不为空, 就遍历该属性指定的类, 创建BeanDefinition, 放到 Set 中;

  4. 如果clients为空, 就根据 value 属性和 basePackages属性和 basePackageClasses 属性指定的值去扫描包, 找到有@FeignClient注解修饰的类, 创建 BeanDefinition, 添加到 Set;

    如果这些属性都为空, 就扫描启动类所在的包;

    basePackageClasses 用法: 该注解指定的类所在的包将被扫描;

  5. 遍历 Set , 获取 BeanDefinition 的 AnnotationMetadata, 进而拿到 @FeignClient 注解的 name 属性( 表示服务名 );

  6. 调用registerFeignClient , 向容器中注册当前 BeanDefinition 对应的一个 FactoryBean;

registerFeignClient

  1. 创建一个FeignClientFactoryBean, 在其 getObejct 方法中, 封装了创建代理对象的逻辑;
  2. getObject方法层层调用, 最终调用了ReflectiveFeign中的一个方法, 该方法使用 JDK 动态代理, 为 @FeignClient 注解修饰的接口, 创建了代理对象;
  3. FeignClientFactoryBean 的 BeanDefinition 添加Spring容器中;

动态代理

  1. 动态代理使用的 InvocationHandlerFeignInvocationHandler (最终是SynchronousMethodHandler)
  2. Handler 的 invoke 方法中, 又经过层层调用, 最终执行了如下逻辑:
  3. 获取 @FeignClient 注解的 name 属性, 通过LoadBanlancerClient 负载均衡地获取一个实例; (所以类加载路径下必须有 LoadBalancerClient 的实现类才行, 换言之, 必须引入 Ribbon 或 LoadBanlancer 之类的组件)
  4. 然后根据被调用的方法的 Mapping 注解, 得到请求路径; 和实例的地址进行拼接, 得到最终的请求地址;
  5. 然后通过 HTTP 工具发送请求;

相关文章:

【Nacos无压力源码领读】(二) 集成 LoadBanlancer 与 OpenFeign

上一篇文章中, 详细介绍了 Nacos 注册中心的原理, 相信看完后, 大家应该完全掌握了 Nacos 客户端是如何自动进行服务注册的, 以及 Nacos 客户端是如何订阅服务实例信息的, 以及 Nacos 服务器是如何处理客户端的注册和订阅请求的; 本文承上启下, 在订阅服务实例的基础上, 介绍如…...

CP AUTOSAR标准之DefaultErrorTracer(AUTOSAR_SWS_DefaultErrorTracer)(更新中……)

1 简介和功能概述 本规范描述了默认错误跟踪器的API。基础软件中检测到的所有开发和运行时错误都会报告给此模块。API参数允许跟踪错误来源和类型: 检测到错误的模块检测到错误的函数错误类型此模块API背后的功能不在本规范的范围内。软件开发人员和软件集成商应根据其特定应用…...

SpringMVC (发送请求——>参数传递—— >响应数据)

设置请求访问路径 RequestMapper&#xff1a;将请求访问路径和我们业务层的方法联系起来 ResponseBody&#xff1a;将我们业务层方法的返回值转化为json&#xff0c;xml或其他格式的数据返回给页面 两种请求 get请求 post请求 测试案例 RequestMapping("/getNameAndAge&…...

认识Modbus RTU与Modbus TCP

&#xff08;选自成都纵横智控-Modbus RTU与Modbus TCP协议区别详解 &#xff09; Modbus RTU 和 Modbus TCP 是两种常用的工业通信协议&#xff0c;用于连接电子设备&#xff0c;但它们在多方面有所不同。以下是它们的详细比较&#xff1a; Modbus RTU 协议类型&#xff1a; …...

如何在 Kubernetes 中使用 ClickHouse 和 JuiceFS

ClickHouse 结合 JuiceFS 一直是一个热门的组合&#xff0c;社区中有多篇实践案例。今天的文章来自美国公司 Altinity&#xff0c;一家提供 ClickHouse 商业服务的企业&#xff0c;作者是 Vitaliy Zakaznikov&#xff0c;他尝试了这个组合并公开了过程中使用的代码。原文有两篇…...

云计算任务调度优化matlab仿真,对比蚁群优化和蛙跳优化

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 ACO蚁群优化 4.2 蛙跳优化 5.完整程序 1.程序功能描述 云计算任务调度优化,优化目标位任务消耗时间&#xff0c;调度后的经济效益以及设备功耗&#xff0c;对比蚁群优化算法和蛙跳优化…...

基于双PI+EKF扩展卡尔曼滤波的PMSM速度控制simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PMSM数学模型 4.2 双PI控制器设计 4.3 扩展卡尔曼滤波器(EKF) 4.4 控制系统实现 5.完整工程文件 1.课题概述 基于双PIEKF扩展卡尔曼滤波的PMSM速度控制simulink建模与仿真。对比基于双PI的扩展卡…...

医疗器械注册资源宝库数屿医械官方平台!

医学影像设备市场作为医疗器械领域的佼佼者&#xff0c;技术门槛高且规模庞大&#xff0c;2021年全球规模达458亿美元&#xff0c;预计2022年逼近500亿美元&#xff0c;增长动力源自技术革新与临床需求攀升。中国市场亦不甘落后&#xff0c;受政策驱动与市场需求双重提振&#…...

Django如何移除数据库字段?

关键步骤&#xff1a; 第一步&#xff1a;python manage.py makemigrations 你的项目名称第二步&#xff1a; python manage.py migrate (.venv) PS D:\python_workpace\django_xitong_shezhi\pythonProject\myproject> python manage.py makemigrations myproject Migra…...

阶段项目——拼图小游戏

Java学习笔记&#xff08;新手纯小白向&#xff09; 第一章 JAVA基础概念 第二章 JAVA安装和环境配置 第三章 IntelliJ IDEA安装 第四章 运算符 第五章 运算符联系 第六章 判断与循环 第七章 判断与循环练习 第八章 循环高级综合 第九章 数组介绍及其内存图 第十章 数…...

基于本地消息表实现分布式事务(最终一致性)

前言 传统单体架构下&#xff0c;所有的功能模块都在一个应用下&#xff0c;所有的代码和业务逻辑都在同一个应用下实现&#xff0c;所以保证数据的一致性就很简单&#xff0c;保证相关操作都在同一个本地事务下就可以了。 但是在微服务架构下&#xff0c;将一个应用拆分成了…...

大数据mapper书写范式hdfs

文章目录 1. 大数据mapper书写范式hdfs 1. 大数据mapper书写范式hdfs import json import sysdef read_input(input_stream):for line in input_stream:yield line.rstrip(\n)def load_json_data(json_line):try:data json.loads(json_line)unique_id data.get(id)combined_…...

ubuntu将软件放到任务栏

右键点击这个 pycharm 方法1&#xff1a; 方法2&#xff1a; sudo nano /usr/share/applications/PyCharm.desktop 编辑这个 [Desktop Entry] NamePyCharm CommentPyCharm Integrated Development Environment Exec/path/to/PyCharm.sh Icon/path/to/PyCharm.svg Terminalf…...

Spring Boot 参数校验 Validation 使用

概述 当我们想提供可靠的 API 接口&#xff0c;对参数的校验&#xff0c;以保证最终数据入库的正确性&#xff0c;是必不可少的活。前、后端校验都是保证参数的准确性的手段之一&#xff0c;前端校验并不安全&#xff0c;任何人都可以通过接口来调用我们的服务&#xff0c;就算…...

基于el-table的表格点选和框选功能

开篇 本篇文章旨在实现一个基于el-table的表格点选和框选功能&#xff0c;除此之外&#xff0c;还支持多种模式的切换、自定义勾选日期等。且&#xff0c;该表格后续可能还会持续优化&#xff01; 功能介绍 表格点选和框选功能&#xff08;没有点击ctrl键的情况下&#xff09;…...

LabVIEW压电陶瓷阻抗测试系统

开发了一种基于LabVIEW软件与PXI模块化仪器的压电陶瓷阻抗测试系统。该系统能在高电压工作条件下测量压电陶瓷的阻抗特性&#xff0c;包括阻抗模值与阻抗角的频率特性&#xff0c;为压电陶瓷的进一步分析与应用提供了重要参考。 项目背景 现有的阻抗测试仪大多只能在低电压条件…...

电销机器人能大幅度提升效率

1、安全稳定性能好 营销机器人的稳定性非常强&#xff0c;在使用性能方面会有更好的优势&#xff0c;而且用的过程中也可以不断的这些模块更新和功能升级&#xff0c;所以会不断的满足大家更多的使用要求&#xff0c;在操作使用的时候非常简单和方便&#xff0c;直接就可以给客…...

虚拟机能访问网页但ping不通百度

最近遇到了奇怪的问题&#xff0c;虚拟机能访问网页&#xff0c;但ping不通百度&#xff0c;记录一下问题的排查过程。 能访问网页&#xff0c;说明DNS、TCP和HTTP没有问题&#xff0c;ping不通&#xff0c;说明ICMP应该出了问题。 首先通过traceroute追踪报文的转发过程&…...

RK3588开发笔记-buildroot编译配置

目录 前言 一、buildroot简介 二、buildroot配置编译 buildroot config配置 buildroot 编译 buildroot 如何单独编译某个软件包 何时需要完全重建 如何完全重建 总结 前言 Rockchip RK3588 是一款强大的多核处理器,广泛应用于边缘计算、人工智能、嵌入式系统等领域。为了在…...

Java设计模式(适配器模式)

定义 将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。 角色 目标抽象类&#xff08;Target&#xff09;&#xff1a;目标抽象类定义客户所需的接口&#xff08;在类适配器中&#xff0c;目标抽象类只能是接口&#xff09;。 适配器类…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...