负载均衡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.rhkb.cn/news/200633.html

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

相关文章

redis的高可用

1.redis的高可用 在集群当中有一个非常重要的指标&#xff0c;提供正常服务的时间的百分比&#xff08;365天&#xff09;99% redis的高可用含义更宽泛&#xff0c;正常服务是指标之一&#xff0c;数据容量的扩展&#xff0c;数据的安全性。 在redis中实现高可用技术&#x…

Oracle实时同步技术

Oracle数据库的价值 Oracle数据库是一种高度可靠、安全和强大的关系型数据库管理系统&#xff0c;它具有以下几个方面的价值&#xff1a; 可靠性和稳定性&#xff1a;Oracle数据库以其高度可靠性、稳定性和数据完整性而闻名于世。 安全性&#xff1a;Oracle数据库提供了一系列…

JVM的垃圾收集算法

1.算法的分类 1.1标记清除算法 第一步&#xff1a;标记&#xff08;找出内存中需要回收的对象&#xff0c;并且把它们标记出来&#xff09; 根据可达性算法&#xff0c;标记的是存活的对象&#xff0c;然后将其他的空间进行回收 第二步&#xff1a;清除&#xff08;清除掉被…

阿里云oss存储文件上传功能实现(保姆级教程)

先登录&#xff1a; 点击进入控制台 点击左上角导航栏按钮 搜索oss&#xff0c;点击进入 进入之后点击立即开通oss按钮&#xff0c;开通之后点击下图立即创建&#xff0c;弹出创建Bucket 填上Bucket名称&#xff0c;读写权限改为公共读。其他不变点击确定创建&#xff0c;完成…

LVS+keepalived——高可用集群

lvskeepalived&#xff1a;高可用集群 keepalived为lvs应运而生的高可用服务。lvs的调度器无法做高可用&#xff0c;于是keepalived这个软件。实现的是调度器的高可用。但是&#xff1a;keepalived不是专门为lvs集群服务的&#xff0c;也可以做其他代理服务器的高可用。 lvs的…

Spring Boot要如何学习?【云驻共创】

Spring Boot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。我这里会分享一些学习Spring Boot的方法和干货&#xff0c;包括…

Python如何实现模板方法设计模式?什么是模板方法设计模式?Python 模板方法设计模式示例代码

什么是模板方法&#xff08;Template Method&#xff09;设计模式&#xff1f; 模板方法&#xff08;Template Method&#xff09;是一种行为型设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤延迟到子类中实现。这种模式允许子类为一个算法的特定步骤提供…

【Flink】Process Function

目录 1、ProcessFunction解析 1.1 抽象方法.processElement() 1.2 非抽象方法.onTimer() 2、Flink中8个不同的处理函数 2.1 ProcessFunction 2.2 KeyedProcessFunction 2.3 ProcessWindowFunction 2.4 ProcessAllWindowFunction 2.5 CoProcessFunction 2.6 ProcessJo…

【Java系列】SpringBoot 集成MongoDB 详细介绍

目录 写在前面 一、步骤介绍 步骤 1: 添加 MongoDB 依赖 步骤 2: 配置 MongoDB 连接信息 步骤 3: 创建实体类 步骤 4: 创建 Repository 接口 步骤 5: 使用 Repository 进行操作 二、特殊处理 写在前面 在Spring Boot中集成MongoDB的过程相对简单&#xff0c;以下是一个…

Linux下使用宏定义判断系统架构和系统类型

文章目录 查看编译器当前支持的宏定义查找指定的宏不同架构不同系统 附录-编译器内部常用的一些宏定义宏定义实际应用使用宏定义判断系统架构使用宏定义判断系统类型 一般情况下在linux下做C/C方面的开发不需要太关注系统架构&#xff0c;当然如果涉及到不同架构下的适配问题&a…

Python---变量的作用域

变量作用域&#xff1a;指的是变量的作用范围&#xff08;变量在哪里可用&#xff0c;在哪里不可用&#xff09;&#xff0c;主要分为两类&#xff1a;局部变量和全局变量。 定义在函数外部的变量就称之为全局变量&#xff1b; 定义在函数内部的变量就称之为局部变量。 # 定义…

基于 Eureka 的 Ribbon 负载均衡实现原理【SpringCloud 源码分析】

目录 一、前言 二、源码分析 三、负载均衡策略 一、前言 如下图&#xff0c;我们在 orderserver 中通过 restTemplate 向 usersever 发起 http 请求&#xff0c;在服务拉取的时候&#xff0c;主机名 localhost 是用服务名 userserver 代替的&#xff0c;那么该 url 是一个可…

Android Studio 引入Xui框架-简单应用

Android Studio Flamingo | 2022.2.1 Patch 2 Android 11开发、Gradle Version 8.0、 jdk17 源代码&#xff1a;GitHub - xuexiangjys/XUI: &#x1f48d;A simple and elegant Android native UI framework, free your hands! (一个简洁而优雅的Android原生UI框架&#xff…

录屏软件自动开启录视频,是如何实现的?

工作要留痕&#xff0c;作为职场人的一项必备技能&#xff0c;因此许多人在做一些重要操作的时候&#xff0c;就会提前开启录屏软件&#xff0c;把操作的每一个步骤进行录制&#xff0c;以避免在出现问题的时候进行检查。当每天都需要在固定的时间点重复某项工作的时候&#xf…

【力扣】从零开始的动态规划

【力扣】从零开始的动态规划 文章目录 【力扣】从零开始的动态规划开头139. 单词拆分解题思路 45. 跳跃游戏 II解题思路 5. 最长回文子串解题思路 1143. 最长公共子序列解题思路 931. 下降路径最小和解题思路 开头 本力扣题解用5题来引出动态规划的解题步骤&#xff0c;用于本…

竞赛选题 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 行人车辆目标检测计数系统 …

【计算机网络笔记】路由算法之距离向量路由算法

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

DAY60 84.柱状图中最大的矩形

84.柱状图中最大的矩形 题目要求&#xff1a;给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼…

【docker】虚拟化和docker容器概念

基础了解 IAAS&#xff1a; 基础设施服务&#xff0c;&#xff08;只提供基础设施&#xff0c;没有系统&#xff09; **SAAS&#xff1a; ** 软件即服务&#xff0c;&#xff08;提供基础设施和系统&#xff09; PAAS&#xff1a; 平台即服务&#xff0c;&#xff08;提供基…

《白帽子讲web安全》

第十四章 PHP安全 文件包含漏洞是“代码注入”的一种。“代码注入”这种攻击&#xff0c;其原理就是注入一段用户能控制的脚本或代码&#xff0c;并让服务器端执行。“代码注入”的典型代表就是文件包含&#xff08;File Inclusion&#xff09;。文件包含可能会出现在JSP、PHP…