负载均衡Ribbon和Feign的使用与区别
Ribbon 的介绍
Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。主要功能是提供客户端的软件负载均衡和服务调用。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer 后面的所有的及其,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用 Ribbon 实现自定义的负载均衡算法
Feign 的介绍
Feign 和 Ribbon 是 Spring Cloud 的 Netflix 中提供的两个实现软负载均衡的组件,Ribbon 和 Feign 都是用于调用其他服务的,方式不同,Feign 则是在 Ribbon 的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建 Http 请求,不过要注意的是抽象方法的注解,方法名要和提供服务的方法对应上。简单点说,Feign 是对 Ribbon 的封装,而且 Feign 和 Ribbon 的作用位置不同。
负载均衡
Ribbon 和 Feign 都是负载均衡技术,那么什么是负载均衡呢?简单点说负载均衡就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
Nginx 服务端负载均衡和 Ribbon 本地负载均衡的区别
Nignx 是服务器负载均衡,客户端所有的请求都会交给 Nginx ,然后由 Nginx 实现转发请求,即负载均衡是由服务端实现的。
Ribbon 本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到 VM 本地,从而在本地实现 RPC 远程服务调用技术。
Ribbon 和 Feign 的区别
- 启动类使用的注解不同,Ribbon 用的是 @RibbonClient,Feign 用的是 @EnableFeignClients 。
- 服务的指定位置不同,Ribbon 是在 @RibbonClient 注解上声明,Feign 则是在定义抽象方法的接口中(service 层的接口上)使用 @FeignClient 声明。
- 调用方式不同,Ribbon 需要自己构建 http 请求,模拟 http 请求然后使用 RestTemplate 发送给其他服务,步骤相当繁琐,Feign 是直接通过接口方式调用。
Ribbon 的使用
项目是建立在springcloud技术篇一 Nacos 的基础上进行的。Ribbon 只是一个客户端的负载均衡器工具,实现起来非常简单,我们只需要注入 RestTemplate 的 Bean 上加上 @LoadBalanced 就可以了,内容如下:
@Configuration
public class WebConfig {public RestTemplate restTemplate() {@LoadBalanced//负载均衡,默认使用轮询规则@Beanreturn new RestTemplate();}
}
补充:在早期版本中,spring-cloud-starter-netflix-eureka-client 依赖已经引入了 Ribbon,则我们可以直接使用,但是因为自从 SpringCloud2020.0.1.0 版本是已经不需要 netflix 了,所以如果我们使用的是最新版本的 springcloud,则需要手动在服务消费方导入 spring-cloud-starter-loadbalancer 依赖支持
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId><version>3.1.1</version>
</dependency>
启动一个消费方,多个服务放进行测试
- 先去修改 springcloud-alibaba-microservice-consumer 工程中的 UserController,然后启动即可
@RestController
@RequestMapping("user-consumer")
public class UserController {@Autowiredprivate DiscoveryClient discoveryClient;//服务发现@Autowiredprivate RestTemplate restTemplate;//用于发送网络请求// 服务方应该调用生产方的服务@RequestMapping("getUsers")public JsonResult getUsers() {// 由于在 WebConfig 中设置了轮询规则,这里通过服务的名称来发送网络请求String url = "http://micro-service-provider/user-provider/findAll";JsonResult jsonResult = restTemplate.getForObject(url,JsonResult.class);System.out.println(jsonResult);return jsonResult;}
}
- 修改 springcloud-alibaba-microservice-provider 工程中的 UserController
@RestController
@RequestMapping("user-provider")
public class UserController {@RequestMapping("findAll")public JsonResult findAll() {// 使用并联启动的方式,启动多个服务提供方进行测试// 先输出 7070,然后修改 application.yml 配置文件,端口号设置为 7070 启动// System.out.println("7070")// 在输出 7071,然后修改 application.yml 配置文件,端口号设置为 7071 启动// System.out.println("7071")// 在输出 7072,然后修改 application.yml 配置文件,端口号设置为 7072 启动// System.out.println("7072")// 模拟数据库数据List<User> users = Arrays.asList(new User(1001, "张三", "123"),new User(1002, "李四", "456"),new User(1003, "王五", "789"),);JsonResult jsonResult = JsonResult.ok();jsonResult.setData(users);return jsonResult;}
}
- 设置 springcloud-alibaba-microservice-provider 工程多次启动


修改端口号,启动多个 provider,然后启动 consumer,访问浏览器进行测试
负载均衡的策略
Ribbon 提供了一个很重要的接口叫做 IRule,其中定义了很多的负载均衡策略,默认的是轮询的方式,一下是 Ribbon 的负载均衡策略

改变 Ribbon 的均衡策略(随机方式):
@Configuration
public class WebConfig {@LoadBalanced//负载均衡@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}// 创建对象实现改变 Ribbon 的负载均衡策略,随机规则@Beanpublic IRule getRule() {return new RandomRule();}
}
自定义方式的均衡策略:
自定义的负载均衡策略需要继承 AbstractLoadBalancerRule 这个类,然后重写 choose 方法,然后将其注入到容器中。
创建 ServerInfo 类
public class ServerInfo {private Server server;private int num;public ServerInfo() {}public ServerInfo(Server server, int num) {this.server = server;this.num = num;}public Server getServer() {return server;}public void setServer(Server server) {this.server = server;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}
}
创建 CustomizeRule 类:
// 自定义规则,每个服务最多访问 5 次,然后再继续访问下一个
public class CustomizeRule extends AbstractLoadBalancerRule {private int limit = 3;// map 的 key 是服务的名字,value 是该服务调用的次数private Map<String, ServerInfo> map = new ConcurrentHashMap<>();@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig){}// 返回值的意思是,当该方法返回什么的时候,那么 Ribbon 或者 Feign 就调用谁。@Overridepublic Server choose(Object key) {Server finalServer = null;ILoadBalancer loadBalancer = getLoadBalancer();// 获取所有的服务List<Server> servers = loadBalancer.getAllServers();// 获取所有的可用的服务List<Server> reachableServers = loadBalancer.getReachableServers();int allServiceSize = servers.size(); // 获取所有服务的长度int upCount = reachableServers.size(); // 获取所有的可用的服务的长度if(0 == allServicesSize || 0 == upCount) {return null;}for(int i = 0; i < allServiceSize; i++) {Server server = servers.get(i);//获取当前遍历的 serverString instanceId = server.getMetaInfo().getInstanceId();String providerName = instanceId.split("@@")[1];//获取服务名ServerInfo serverInfo = map.get(providerName);//获取对应服务// 首次调用if(null == serverInfo) {serverInfo = new ServerInfo(server, 1);map.put(providerName, serverInfo);finalServer = server;break;} else {// 不为空,表示之前肯定调用过// 当前遍历的 server 与正在调用的 server 是同一个 serverif(serverInfo.getServer().getId().equals(server.getId())) {// 如果没有满 3 次,接着走该服务。// 如果满了 3 次,接着下个int num = serverInfo.getNum();//获取已经调用的次数if(num >= limit) {// 超出了 3 次// 超出次数,要走下一个,需要判断是否有下一个,需要判断是否有下一个,如果没有下一个,就回到第一个if(i == (allServiceSize - 1)) {Server firstServer = servers.get(0);//如果为最后一个就拿第一个ServerInfo firstServerInfo = new ServerInfo(firstServer, 1);map.put(providerName, firstServerInfo);finalServer = firstServer;} else {Server nextServer = servers.get(i + 1);map.put(providerName, nextServerInfo);finalServer = nextServer;}break;} else {serverInfo.setNum(++num);finalServer = server;break;}}}}return finalServer;}
}
修改 WebConfig ,添加配置
@Configuration
public class WebConfig {@Bean@LoadBalanced//负载均衡,默认规则:轮询public RestTemplate getRestTemplate() {return new RestTemplate();}// 自定义均衡负载服务器@Beanpublic IRule getRule() {return new CustomizeRule();}
}
Feign 的使用
在 springcloudalibaba-micro-service-consumer 的 pom.xml 中导入依赖
<!-- Feign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.6.RELEASE</version>
</dependency>
在启动类上加入 @EnableFeignClients 的注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class,args);}
}
创建UserService
@Service
@FeignClient("micro-service-provider")
public interface UserService {@RequestMapping("/user-provider/findAll")public JsonResult findAll();
}
创建 FeignUserController
@RestController
@RequestMapping("feign")
public class FeignUserController {@Autowiredprivate UserService userService;@RequestMapping("findAll)public JsonResult findAll() {return userService.findAll();}
}
启动多个 provider,然后启动 consumer,访问
http://localhost:8080/feign/findAll 进行测试
在 Feign 的基础上的服务之间的传参
在 springcloudalibaba-micro-service-provide 工程中的 UserController 添加 CRUD 方法
@RestController
@RequestMapping("user-provider")
public class UserController {@RequestMapping("findAll")public JsonResult findAll(){//使用并联启动的方式,启动多个服务提供方进行测试//先输出7070,然后修改application.yml配置文件,端口设置为7070启动//System.out.println("7070");//再输出7071,然后修改application.yml配置文件,端口设置为7071启动System.out.println("7071");//再输出7072,然后修改application.yml配置文件,端口设置为7072启动//System.out.println("7072");List<User> users = Arrays.asList(new User(1001, "张三", "123"),new User(1002, "李四", "456"),new User(1003, "王五", "789"));JsonResult jsonResult = JsonResult.ok();jsonResult.setData(users);return jsonResult;}//模拟数据库操作//查询单个@GetMapping("findById")public JsonResult findById(@RequestParam("id") Integer id){User user = new User(id, "jack", "123");JsonResult jsonResult = JsonResult.ok();jsonResult.setData(user);return jsonResult;}//删除单个-restful风格的开发@DeleteMapping("deleteById/{id}")public JsonResult deleteById(@PathVariable("id") Integer id){System.out.println("deleteById:"+id);return JsonResult.ok();}//添加@PostMapping("addUser")public JsonResult addUser(@RequestBody User user){System.out.println("addUser:"+user);return JsonResult.ok();}//修改 如果参数不一致 RequestParam(value = "")@PutMapping("updateUser")public JsonResult updateUser(@RequestParam Integer id,@RequestParam String username,@RequestParam String password){System.out.println("updateUser:"+id+"--"+username+"--"+password);return JsonResult.ok();}
}
在 springcloudalibaba-micro-service-consumer 工程中的 UserService 添加对应方法
@Service
@FeignClient("micro-service-provider")
public interface UserService {@RequestMapping("/user-provider/findAll")public JsonResult findAll();//模拟数据库操作//查询单个@GetMapping("/user-provider/findById")public JsonResult findById(@RequestParam("id") Integer id);//删除单个@DeleteMapping("/user-provider/deleteById/{id}")public JsonResult deleteById(@PathVariable("id") Integer id);//添加@PostMapping("/user-provider/addUser")public JsonResult addUser(@RequestBody User user);//修改@PutMapping("/user-provider/updateUser")public JsonResult updateUser(@RequestParam Integer id,@RequestParam String username,@RequestParam String password);}
在 springcloudalibaba-micro-service-consumer 工程中的 FeignUserController 添加对应方法
@RestController
@RequestMapping("feign")
public class FeignUserController {@Autowiredprivate UserService userService;@RequestMapping("findAll")public JsonResult findAll(){return userService.findAll();}//模拟数据库操作//查询单个@GetMapping("findById")public JsonResult findById(@RequestParam("id") Integer id){return userService.findById(id);}//删除单个@DeleteMapping("deleteById/{id}")public JsonResult deleteById(@PathVariable("id") Integer id){return userService.deleteById(id);}//添加 使用requestbody注解前端需要传送JSON数据@PostMapping("addUser")public JsonResult addUser(User user){return userService.addUser(user);}//修改@PutMapping("updateUser")public JsonResult updateUser(@RequestParam Integer id,@RequestParam String username,@RequestParam String password){return userService.updateUser(id,username,password);}
}
相关文章:
负载均衡Ribbon和Feign的使用与区别
Ribbon 的介绍 Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。主要功能是提供客户端的软件负载均衡和服务调用。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer…...
Python Opencv实践 - 二维码和条形码识别
使用pyzbar模块来识别二维码和条形码。ZBar是一个开源软件,用来从图像中读取条形码,支持多种编码,比如EAN-13/UPC-A、UPC-E、EAN-8、代码128、代码39、交错2/5以及二维码。 pyzbar是python封装ZBar的模块,我们用它来做条形码和二维码的识别。…...
树莓派的的串口通信协议
首先,回顾一下串口的核心知识点,也是面试重点: 串口通信通常使用在多机通讯中串口通信是全双工的决定串口通信的成功与否的是 数据格式 和 波特率数据格式:1. 数据位 2.停止位 3. 奇偶校验位 树莓派恢复串口 回忆前几节树莓派刷机…...
DAY60 84.柱状图中最大的矩形
84.柱状图中最大的矩形 题目要求:给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼…...
你知道Linux操作系统的前世今生吗?Linux系统又该如何搭建呢?
文章目录 前言1. Linux 是什么1.1 Unix & Linux 发展历程图1.2 Linux 的发展1.3 Linux 的发行版 2. Linux 环境搭建2.1 环境搭建方式2.2 使用云服务器 3. 使用终端软件连接到 Linux3.1 什么是终端软件3.2 下载安装 XShell3.3 使用 XShell 登陆主机 总结 前言 可能很多人都…...
674. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l < i < r,都有 nums[i] < nums[i 1] &a…...
DS5上ARM编译器样例工程改为GCC编译
想问一下,DS5上ARM编译器通过的样例工程,换成aarch64-none-elf-gcc工具链,是不是需要把startup.S改成gcc支持的格式呀?怎么改呢,求助大神们指点一下!谢谢!...
关于Unity Time.deltaTime的理解和使用
Unity中的Time.deltaTime是一个表示上一帧到当前帧所用时间的浮点数。 它可以让Unity应用程序能够以平滑的方式在不同的帧率下运行。 要深刻理解Time.deltaTime,首先得了解Unity引擎得工作原理。 Unity引擎以每秒帧数(FPS)的形式运行。 比…...
Vue3 配置全局 scss 变量
variables.scss $color: #0c8ce9;vite.config.ts // 全局css变量css: {preprocessorOptions: {scss: {additionalData: import "/styles/variables.scss";,},},},.vue 文件使用...
45.120.101.X 如何找出网站建设中弱点和漏洞
漏洞扫描服务(Vulnerability Scan Service)集Web漏洞扫描、操作系统漏洞扫描、资产内容合规检测、配置基线扫描、弱密码检测五大核心功能,自动发现网站或服务器在网络中的安全风险,为云上业务提供多维度的安全检测服务,…...
linux 下打印堆栈信息 jstack pstack gstack 有啥区别?分别的使用场景是啥?
jstack、pstack和gstack是在Linux系统下用于打印堆栈信息的工具,它们的使用场景和功能略有不同。 jstack:jstack是Java虚拟机自带的工具,用于打印Java进程的堆栈信息。它可以显示Java线程的状态、锁信息、线程堆栈等。jstack主要用于诊断Java…...
Vue 3实战:打造交互丰富的任务管理应用
Vue 3实战:打造交互丰富的任务管理应用 前言搭建Vue 3项目步骤 1: 安装Vue CLI 3步骤 2: 创建Vue 3项目步骤 3: 进入项目目录步骤 4: 启动项目步骤 5: 查看项目结构 组件设计与复用1. **组件的职责单一化:**2. **Props传递:**3. **插槽(Slots)…...
python之列表
列表常用操作 l [1,2,3,4,5]# 列表之切片 l1 l[:3] print(l1) # [1, 2, 3],结果为下标0到2 l2 l[3:] print(l2) # [4, 5] ,从下标3开始直到结束 l3 l[1:-1] print(l3) # [2, 3, 4] , 去头去尾...
想要保护服务器的安全,使用哪个软件比较好?
随着互联网的发展普及,网络安全问题也越发凸显,相信不少使用服务器的用户,有遇到过或是听过服务器被入侵导致数据丢失或是被植入病毒木马程序被用来挖矿的情况。那么面对这类情况,我们该如何做好安全工作来保障我们服务器的使用安…...
gitlab图形化界面使用
gitlab使用 创建用户 上面是创建用户基本操作 修改密码 创建组 给组添加用户 创建项目 选择空白项目 退出root用户,切换其他用户 在服务器上创建ssh密钥 使用ssh-ketgen 命令 新服务器上创建的 [rootgitlab ~]# ssh-keygen Generating public/private rsa key …...
Vue使用基本教程(基本介绍及对比,初步使用,构建项目,编辑器等)
一、Vue及与其他前端框架的异同。 Vue.js(通常简称为Vue)是一个用于构建用户界面的渐进式JavaScript框架。它专注于视图层,采用简单的API设计,使得开发者能够更轻松地构建交互式的单页面应用(SPA)和用户界…...
基恩士软件的基本操作(四,快速编辑plc技巧)
目录 单元软原件注释快速添加 双击单元配置,进入单元编辑器 KV一键添加注释 双击软元件注释 进入软元件编辑界面 ,对弹出的列表中软元件打勾点击登录 元件注释就自动添加了 注释收索,快速编辑软元件 自定义注释收索 空软元件快速查找 …...
通达信的ebk文件
我们在通达信软件中 调出 “自定义板块设置” 这个菜单,点击“导出”,会提示你存储 “自选股.EBK”,其实就是对自定义板块里的目录进行备份的一种方式, 当我们打开 这个文件,你会发现其实就是存储了 股票代码ÿ…...
城市易涝点怎么安装万宾科技内涝积水监测仪?
城市内涝是多个城市广泛存在的问题,经常给城市的居民和基础设施带来一些安全威胁。暴雨引发的道路积水和交通中断、财产损失,甚至公共安全威胁都是城市管理者需要提前预防的问题。为了解决这些问题,内涝积水监测仪的应用是一大重要的举措&…...
css取消移动端长按元素背景色
在开发微信小程序的时候,发现有的元素长按之后,出现了讨厌人的背景色,这就很奇怪,就想把它去掉,所以这里教一下方法: 在所在元素添加css样式: // 取消长按的背景色-webkit-tap-highlight-color:…...
别再傻傻打全称了!LaTeX/BibTeX用户如何一键搞定IEEE引用格式(含期刊会议缩写库)
LaTeX/BibTeX高效引用:IEEE期刊会议缩写自动化解决方案 引言 每次在LaTeX论文中引用IEEE文献时,你是否都要手动输入完整的期刊会议名称?当参考文献列表中出现格式不统一的缩写时,审稿人会不会皱眉?作为计算机、电子工程…...
告别卡顿!用Mesh Shader在Unity里渲染百万级模型(附HLSL代码)
百万级模型流畅渲染实战:Unity中Mesh Shader的深度应用 当你在Unity中加载一个包含数十万面数的城市模型时,是否经历过帧率瞬间跌至个位数的绝望?传统渲染管线在面对复杂几何体时的力不从心,正是Mesh Shader技术要解决的核心痛点。…...
告别‘炼丹炉’:用ncnn+ONNX把PyTorch模型轻松‘瘦身’部署到边缘设备
从PyTorch到边缘设备:ncnnONNX轻量化部署实战指南 边缘计算时代的模型部署挑战 当我们将训练好的PyTorch模型部署到边缘设备时,常常会遇到这样的困境:在开发机上运行流畅的模型,到了树莓派或移动设备上却变得异常缓慢࿰…...
StageVAR:自回归模型分阶段加速框架解析
1. 项目背景与核心价值在计算机视觉领域,自回归模型(Autoregressive Models)因其出色的序列建模能力,已成为图像生成、视频预测等任务的主流选择。但这类模型存在一个致命痛点——推理速度慢。传统自回归模型需要逐像素或逐块生成…...
别再浪费FPGA的BRAM了!手把手教你用Verilog实现只存1/4周期的DDS IP核(附完整Matlab生成coe代码)
FPGA资源优化实战:用1/4周期存储实现高效DDS设计 在FPGA开发中,Block RAM(BRAM)是极其宝贵的硬件资源。当项目需要实现多个DDS(直接数字频率合成)模块时,传统的全周期波形存储方法会快速耗尽BRA…...
ROS2 不只是节点通信
公众号致力于点云处理,SLAM,三维视觉,具身智能,自动驾驶等领域相关内容的干货分享,欢迎各位加入,有兴趣的可联系dianyunpcl163.com。文章未申请原创,未经过本人允许请勿转载,有意转载…...
PCL2启动器架构深度解析:如何通过模块化设计解决Minecraft环境管理难题
PCL2启动器架构深度解析:如何通过模块化设计解决Minecraft环境管理难题 【免费下载链接】PCL Minecraft 启动器 Plain Craft Launcher(PCL)。 项目地址: https://gitcode.com/gh_mirrors/pc/PCL Plain Craft Launcher 2(PC…...
MotionGPT3:基于大语言模型的文本与3D动作生成技术解析
1. 项目概述:当大语言模型学会“看”动作最近在探索多模态大模型的应用边界时,我深度体验了一个名为“MotionGPT3”的开源项目。这个项目来自OpenMotionLab,它的核心目标非常明确:让大语言模型(LLM)不仅能理…...
代码内f12跳转至调用方法失败,弹窗显示hp programmable key未安装
解决方案:按组合键FNShift即可切换模式,F12就可以跳转至调用方法位置。...
【沈阳航空航天大学主办 | JPCS(ISSN:1742-6596)出版 | 往届均已见刊并完成EI 和Scopus检索】第六届计算机、遥感与航空航天国际学术会议(CRSA 2026)
第六届计算机、遥感与航空航天国际学术会议(CRSA 2026) 2026 6th International Conference on Computer, Remote Sensing and Aerospace 大会时间: 2026年6月26-28日 大会地点:中国-辽宁-沈阳 会议官网:www.iccrsa.org【参…...
