负载均衡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//负载均衡,默认使用轮询规则
		@Bean
		return 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 {
	@Autowired
	private DiscoveryClient discoveryClient;//服务发现
	
	@Autowired
	private 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//负载均衡
	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
	
	// 创建对象实现改变 Ribbon 的负载均衡策略,随机规则
	@Bean
	public 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<>();
	
	@Override
	public void initWithNiwsConfig(IClientConfig iClientConfig){}
	
	// 返回值的意思是,当该方法返回什么的时候,那么 Ribbon 或者 Feign 就调用谁。
	@Override
	public 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);//获取当前遍历的 server
			String 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 是同一个 server
				if(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();
	}
	// 自定义均衡负载服务器
	@Bean
	public 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 {
	@Autowired
	private 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 {
 
    @Autowired
    private 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);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

“茶叶创新:爆改营销策略,三个月狂销2300万“

我的朋友去年制作了一款白茶&#xff0c;并在短短三个月内将其销售量推到了2300万的高峰。你相信吗&#xff1f; 这位朋友并没有任何茶叶方面的经验&#xff0c;他只是一个有着冒险精神的企业家。他先找到了一家代工厂&#xff0c;帮助他把他的茶叶理念转化为现实。 当他把茶叶…

小趴菜教你如何用Python开发手机App..

Python语言虽然很万能&#xff0c;但用它来开发app还是显得有点不对路&#xff0c;因此用Python开发的app应当是作为编码练习、或者自娱自乐所用&#xff0c;加上目前这方面的模块还不是特别成熟&#xff0c;bug比较多&#xff0c;总而言之&#xff0c;劝君莫轻入。 准备工作 …

Java修仙记之记录一次与前端女修士论道的经历

文章开始之前&#xff0c;想跟我念一句&#xff1a;福生无量天尊&#xff0c;无量寿佛&#xff0c;阿弥陀佛 第一场论道&#xff1a;id更新之争 一个天气明朗的下午&#xff0c;前端的小美女长发姐告诉我&#xff1a;嘿&#xff0c;小后端&#xff0c;你的代码报错了 我答道&am…

【旅游行业】Axure旅游社交平台APP端原型图,攻略门票酒店民宿原型案例

作品概况 页面数量&#xff1a;共 110 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;旅游平台&#xff0c;酒店住宿 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「旅游社交平台」移动端…

每日一练 | 华为认证真题练习Day134

1、开启标准STP协议的交换机可能存在哪些端口状态&#xff1f;&#xff08;多选&#xff09; A. Discarding B. Listening C. Disabled D. Forwarding 2、下列路由协议中优先级最高的是&#xff1f; A. Direct B. RIP C. OSPF D. Static 3、参考如图所示的输出结果&…

如何使用API接口对接淘宝获取店铺销量排序,店铺名称等参数

要接入淘宝官方开放平台API接口获取店铺销量排序&#xff0c;店铺名称等参数&#xff0c;需要按照以下步骤进行操作&#xff1a; 找到可用的API接口&#xff1a;首先&#xff0c;需要找到支持查询店铺信息的API接口。可以在电商数据平台的开放平台上查找相应的API接口。注册并…

PHP 进阶之路 - 亿级 pv 网站架构实战之性能优化

PHP 进阶之路 - 亿级 pv 网站架构实战之性能优化 缘起 PV和PU&#xff08;数据分析—业务指标&#xff09; PV即访问次数——用户每访问一次可以看作一次PV。 PU即访问人数——在同一天内&#xff0c;一个用户无论访问了多少次都算一个访客。 通过PV和PU可以分析出用户喜欢…

【无公网IP内网穿透】异地远程访问本地SQL Server数据库

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.本地网页发布 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 1.前言 数据库的重要性相信大家…

智慧安防监控系统EasyCVR(v3.4)开放协议的介绍及使用

安防视频监控系统EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、视频能力灵活&#xff0c;能…

MS90C386:+3.3V 175MHz 的 24bit 平板显示器(FPD)LVDS 信号接收器

产品简述 MS90C386 芯片能够将 4 通道的低压差分信号&#xff08; LVDS &#xff09;转换成 28bit 的 TTL 数据。时钟通道与数据通道并行输入。在时钟频率 为 175MHz 时&#xff0c; 24bit 的 RGB 数据、 3bit 的 LCD 时序数据和 1bit 的控制数据以 1225Mb…

electron桌面应用webSoket实时弹框提示实现

一、实现效果&#xff1a;网页端或者移动端进行了审核操作&#xff0c;在电脑右下角提示用户查看。 1、当有弹框提示的情况时&#xff0c;会弹出如下提示&#xff0c;点击查看自动跳转到当前地址&#xff0c;点击关闭则关闭当前提示窗口&#xff1b; 2、当有两条及其以上的消息…

redis--高可用之持久化

redis高可用相关知识 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服务( 如主…

前端css粘性布局,顶部吸附效果(position: sticky)

sticky属性设置 /* 设置粘性布局 */ position: sticky; /* 拖动滚动条&#xff0c;当前元素超出文档0的位置时&#xff0c;触发定位效果&#xff08;同级元素位置不会受影响&#xff09; */ top: 0;页面初始效果 设置前&#xff08;滚动页面时&#xff0c;标签栏随页面滚动&a…

数字电路的基础知识

一、数字电路概述 用数字信号完成对数字量进行逻辑运算和算术运算的电路称为数字电路。 由于它具有逻辑运算和逻辑处理功能&#xff0c;所以又称为数字逻辑电路。 现代的数字电路由半导体工艺制成的数字集成器件构造而成。 逻辑门是数字电路的基本单元电路&#xff0c;就如同在…

海康威视监控相机的SDK与opencv调用(非工业相机)

1.研究内容 本篇主要对海康威视的监控相机的SDK回调进行研究&#xff0c;并于opencv结合&#xff0c;保存图像,以供后续其他处理&#xff0c;开发语言为C 2.步骤及方法 2.1 海康SDK介绍 海康SDK下载地址 根据自身编译环境&#xff0c;下载对应的SDK&#xff0c;需要注意的是…

百度爬虫的工作原理解析

百度作为中国最大的搜索引擎&#xff0c;其工作原理备受关注。本文将深入探讨百度爬虫的工作原理&#xff0c;介绍其基本流程以及关键技术&#xff0c;帮助读者更好地理解搜索引擎背后的技术核心。 百度爬虫是百度搜索引擎的重要基石&#xff0c;它们被广泛用于收集互联网上的网…

竞赛选题 身份证识别系统 - 图像识别 深度学习

文章目录 0 前言1 实现方法1.1 原理1.1.1 字符定位1.1.2 字符识别1.1.3 深度学习算法介绍1.1.4 模型选择 2 算法流程3 部分关键代码 4 效果展示5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计 图像识别 深度学习 身份证识别…

创建域名邮箱邮件地址的方法与步骤

如何创建域名邮箱邮件地址?使用Zoho Mail创建域名邮箱邮件地址的步骤简单易懂&#xff0c;操作便捷。从其他邮箱迁移到Zoho Mail的过程也相当顺畅&#xff0c;您可以轻松为所有员工创建具有企业邮箱域名的电子邮件地址。 步骤1&#xff1a;添加并验证您的域名 首先&#xff0c…

fastdfs-client-java-1.30 maven 打包安装

1. 进入源代码目录&#xff0c;打开cmd mvn clean install 或者 mvn package 问题不大的话会在同级目录target目录下生成打包后文件 2. 当前目录下cmd进行maven安装 mvn install:install-file -DgroupIdorg.csource -DartifactIdfastdfs-client-java -Dversion${version} -D…

设计模式—命令模式

1.什么是命令模式&#xff1f; 命令模式是一种行为型设计模式&#xff0c;核心是将每种请求或操作封装为一个独立的对象&#xff0c;从而可以集中管理这些请求或操作&#xff0c;比如将请求队列化依次执行、或者对操作进行记录和撤销。 命令模式通过将请求的发送者&#xff0…