负载均衡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>

启动一个消费方,多个服务放进行测试

  1. 先去修改 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;}
}
  1. 修改 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;}
}
  1. 设置 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);}
}

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

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

相关文章

JVM基础- 垃圾回收器

基本介绍 Java虚拟机&#xff08;JVM&#xff09;中的垃圾回收器是用来自动管理内存的关键组件。它负责识别并回收不再使用的内存&#xff0c;从而防止内存泄漏。不同的JVM实现提供了多种垃圾回收器&#xff0c;每种回收器都有其特定的使用场景和性能特点。以下是一些常见的JV…

【用unity实现100个游戏之16】Unity程序化生成随机2D地牢游戏2(附项目源码)

文章目录 先看看最终效果前言生成走廊生成房间修复死胡同增加走廊宽度获取走廊位置信息集合方法一方法二 源码完结 先看看最终效果 前言 上期已经实现了房间的生成&#xff0c;本期紧跟着上期内容&#xff0c;生成走廊并结合上期内容生成连通的房间。 生成走廊 修改Procedur…

集成多元算法,打造高效字面文本相似度计算与匹配搜索解决方案,助力文本匹配冷启动[BM25、词向量、SimHash、Tfidf、SequenceMatcher]

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

zabbix的安装配置,邮件告警,钉钉告警

zabbix监控架构 zabbix优点 开源&#xff0c;无软件成本投入server对设备性能要求低支持设备多&#xff0c;自带多种监控模板支持分布式集中管理&#xff0c;有自动发现功能&#xff0c;可以实现自动化监控开放式接口&#xff0c;扩展性强&#xff0c;插件编写容易当监控的item…

力扣C++学习笔记——C++ 给vector去重

要使用std::set对std::vector进行去重操作&#xff0c;您可以将向量中的元素插入到集合中&#xff0c;因为std::set会自动去除重复元素。然后&#xff0c;您可以将集合中的元素重新存回向量中。以下是一个示例代码&#xff0c;演示如何使用std::set对std::vector进行去重&#…

Linux系统编程 系统编程概念

1.系统调用 系统调用&#xff08;system call&#xff09;其实是 Linux 内核提供给应用层的应用编程接口&#xff08;API&#xff09;&#xff0c;是 Linux 应用层进入内核的入口。不止 Linux 系统&#xff0c;所有的操作系统都会向应用层提供系统调用&#xff0c;应用程序通过…

为什么Transformer模型中使用Layer Normalization(Layer Norm)而不是Batch Normalization(BN)

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

GCC 学习

GCC Resource Center for GCC Internalshttps://www.cse.iitb.ac.in/grc/这是个不错资料网站&#xff0c;有兴趣的可以了解下

本地搭建Stackedit Markdown编辑器结合内网穿透实现远程访问

文章目录 1. docker部署Stackedit2. 本地访问3. Linux 安装cpolar4. 配置Stackedit公网访问地址5. 公网远程访问Stackedit6. 固定Stackedit公网地址 StackEdit是一个受欢迎的Markdown编辑器&#xff0c;在GitHub上拥有20.7k Star&#xff01;&#xff0c;它支持将Markdown笔记保…

AR远程辅助技术应用到气象部门有何好处?

随着科技的不断发展&#xff0c;人类对于自然环境的理解和掌控能力也在不断提升。其中&#xff0c;AR(增强现实)技术的应用&#xff0c;为气象监控带来了革命性的变化。AR气象远程监控&#xff0c;就是将AR技术与气象监控相结合&#xff0c;通过虚拟与现实的融合&#xff0c;实…

Hive安装配置 - 本地模式

文章目录 一、Hive运行模式二、安装配置本地模式Hive&#xff08;一&#xff09;安装配置MySQL1、删除系统自带的MariaDB2、上传MySQL组件到虚拟机3、在主节点上安装MySQL组件4、在主节点上配置MySQL&#xff08;1&#xff09;查看MySQL服务状态&#xff08;2&#xff09;查看M…

蓝桥杯每日一题2023.11.18

题目描述 蓝桥杯大赛历届真题 - C 语言 B 组 - 蓝桥云课 (lanqiao.cn) 题目分析 本题使用搜索&#xff0c;将每一个格子进行初始赋值方便确定是否为相邻的数&#xff0c;将空出的两个格子首先当作已经填好数值为100&#xff0c;此时从第一个格子右边的格子开始搜索&#xff…

实在智能出席山东省数据科学大会,构建产学研教数智创新生态

11月18日至19日&#xff0c;由山东大学、山东省科学技术协会、山东省大数据局主办的首届“山东省数据科学大会暨泰山科技论坛”在山东大学&#xff08;中心校区&#xff09;隆重召开&#xff0c;以“数聚慧能 科创未来”为主题&#xff0c;来自全国各地的高校、科研机构、企事业…

电脑上可以写便签的软件哪些界面比较可爱且好用?

电脑上可以安装使用的便签类软件比较多&#xff0c;在选择使用电脑便签软件时&#xff0c;很多人对便签的外观界面还是比较在意的&#xff0c;一个好看的便签界面在一方面可以引起大家的注意&#xff0c;另一方面可以增加电脑桌面背景和便签类软件的协调性。 电脑便签软件通常…

每日一练:X加上100为完全平方数,再加上168任然为完全平方数

题目 一个整数&#xff0c;它加上100后是一个完全平方数&#xff0c;再加上168又是一个完全平方数&#xff0c;请问该数是多少&#xff1f; 实现方式1 解题思路 设整数为x&#xff0c;根据题意建立方程&#xff1a;   (1) x 100 是一个完全平方数&#xff0c;即存在整数a满…

JavaWeb开发——文件上传

1 简介 文件上传&#xff1a;将本地图片、视频、音频等文件上传到服务器&#xff0c;供其他用户浏览或下载的过程 文件上传涉及到两部分&#xff1a;前端程序 服务端程序 前端程序 【三要素】&#xff1a;① 需要定义一个form 表单&#xff0c;且表单里需定义一个类型为“ …

使用centos搭建内网的yum源

1.安装httpd服务 2.启动服务&#xff0c;设置开机自启 #启动服务 systemctl start httpd # 设置开机自动启动 systemctl enable httpd systemctl status httpd3.新建一个目录&#xff0c;将rpm文件放到该目录下 4.将/etc/httpd/conf/httpd.conf文件中的DocumentRoot "…

Qt专栏3—Qt项目创建Hello World

setp1 打开软件 双击Qt Creator 11.0.3 (Community)&#xff0c;打进入软件界面 step2 创建项目 点击创建项目 step3 选择模板 选着Application&#xff08;Qt&#xff09;->Qt Widgets Application setp4 设置项目 名称中填入项目号名&#xff0c;创建路径中填入项目保存位…

每日一题(LeetCode)----链表--两两交换链表中的节点

每日一题(LeetCode)----链表–两两交换链表中的节点 1.题目&#xff08;[24. 两两交换链表中的节点](https://leetcode.cn/problems/spiral-matrix/)&#xff09; 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内…