【Spring Cloud 四】Ribbon负载均衡

Ribbon负载均衡

  • 系列文章目录
  • 背景
  • 一、什么是Ribbon
  • 二、为什么要有Ribbon
  • 三、使用Ribbon进行负载均衡
    • 服务提供者A代码
      • pom文件
      • yml配置文件
      • 启动类
      • controller
    • 服务提供者B
      • pom文件
      • yml配置文件
      • 启动类
      • controller
    • 服务消费者
      • pom文件
      • yml文件
      • 启动类
      • controller
    • 运行测试
  • 四、Ribbon的负载均衡策略
    • Ribbon核心接口
    • Ribbon提供的负载均衡算法
    • 配置此消费者嗲用任何服务都用某种负载均衡策略
    • 访问不同的服务使用不同的算法规则
  • 总结

系列文章目录

【Spring Cloud一】微服务基本知识
【Spring Cloud 三】Eureka服务注册与服务发现


背景

目前公司项目使用的注册中心主要是Spring Cloud Alibaba的Nacos做的注册中心和配置中心。并且Nacos使用了Ribbon作为默认的负载均衡器。但是相当于将Ribbon的负载均衡给透明化了,日常开发明面上是看不到Ribbon的。所以出于提升自己的角度,博主对Ribbon进行了理论学习并进行了实践。

一、什么是Ribbon

Spring Cloud Ribbon它是一个基于HTTP和TCP的客户端负载均衡工具,它是基于Netflix Ribbon实现的。通过Spring Cloud的封装,可以让我们轻松的面向服务的REST模板请求自动转换为客户端负载均衡的服务调用。

Ribbon主要干什么工作:它用在服务消费者需要调用多个相同功能的服务提供者实例时,帮助决定选择哪个服务提供者实例来完成调用。Ribbon可以通过多种负载均衡策略(随机、轮询、加权 、iphash)等方式,将请求分配到不同的服务实例上,以实现负载均衡和高可用。

二、为什么要有Ribbon

总体来说Ribbon是为了解决在微服务架构中服务调用的负载均衡和容错问题而引入的。

Ribbon解决了以下关键问题:

  1. 负载均衡:通过不同势力之间分配负载,Ribbon可以使系统更加稳定和高效,防止某个实例过载而导致服务不可用。
  2. 容错和自动恢复:如果调用的服务实例发生故障或不可用,Ribbon会自动尝试从其他健康的实例中选择一个进行请求处理,这种机制可以提高系统的可靠性和健壮性。
  3. 多种负载均衡策略:可以允许根据实际需求进行定制,更好的满足不同的应用场景。

三、使用Ribbon进行负载均衡

补充:Ribbon作为服务消费者的负载均衡器,有两种使用方式,一种是和RestTemplate相结合,另一种是和OpenFeign相结合。OpenFeign已经默认集成了Ribbon。

例系统中总共有四个服务,一个是Eureka来做服务注册和服务发现,两个服务提供者,一个服务消费者。
Eureka已经在这篇博客进行了实践【Spring Cloud 三】Eureka服务注册与服务发现,本篇博客不在进行一步一步搭建。

服务提供者A代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>provider-a</artifactId><version>0.0.1-SNAPSHOT</version><name>provider-a</name><description>provider-a</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml配置文件


server:port: 8080spring:application:name: providereureka:client:service-url: defaultZone: http://localhost:8761/eureka #eureka服务端和客户端的交互地址,不写的话默认是 8761,集群的话地址用,隔开。register-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

@SpringBootApplication
@EnableEurekaClient
public class ProviderAApplication {public static void main(String[] args) {SpringApplication.run(ProviderAApplication.class, args);}}

controller

@RestController
public class ProviderController {@GetMapping("hello")public String hello(){return "我是服务提供者A";}
}

服务提供者B

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>provider-b</artifactId><version>0.0.1-SNAPSHOT</version><name>provider-b</name><description>provider-b</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml配置文件


server:port: 8081spring:application:name: providereureka:client:service-url: defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

@SpringBootApplication
@EnableEurekaClient
public class ProviderBApplication {public static void main(String[] args) {SpringApplication.run(ProviderBApplication.class, args);}}

controller

@RestController
public class ProviderController {@GetMapping("hello")public String hello(){return "我是服务提供者B";}
}

服务消费者

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>consumer</artifactId><version>0.0.1-SNAPSHOT</version><name>consumer</name><description>consumer</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId><version>2.2.9.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml文件

server:port: 8082spring:application:name: consumereureka:client:service-url: defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔ribbon:eager-load:enabled: false #ribbon只有自己的话是不能做服务发现,需要借助eureka。如果为false表示懒加载,请求调用的时候开启。如果为true表示程序启动的时候开启eureka:enabled: truehttp: #我们使用ribbon用的是RestTemplate发请求。底层是java.net.HttpUrlConnection发的请求, 很方便但是不支持连接池client:  # 发送请求的工具有很多如:httpClient 它支持连接池,效率更好。如果你想该请求的工具,需要添加对应的依赖。enabled: falseokhttp:   #这个也是请求工具,移动端用的比较多, 轻量级请求enabled: false

启动类

@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}/*** 这个RestTemplate* 添加上了LoadBalanced 它会被ribbon来操作* @return*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}}

controller

@RestController
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("testRibbon")public String testRibbon(String serviceName){String result = restTemplate.getForObject("http://" + serviceName + "/hello", String.class);return result;}
}

运行测试

先运行Eureka服务,再运行服务提供者最后运行服务消费者。
调用接口的实现效果:Ribbon默认的负载均衡策略是轮询,及A——B——A——B。
在这里插入图片描述
在这里插入图片描述

四、Ribbon的负载均衡策略

Ribbon核心接口

根据负载均衡策略从所有对应的服务中选取一个服务
在这里插入图片描述

Ribbon提供的负载均衡算法

  1. com.netflix.loadbalancer.RoundRobinRule 轮询
  2. com.netflix.loadbalancer.RandomRule 随机
  3. com.netflix.loadbalancer.WeightedResponseTimeRule 权重轮询
  4. com.netflix.loadbalancer.AvailabilityFilteringRule 会先过滤掉由于多次访问故障处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对于剩余的服务按照轮询的策略进行访问。
  5. com.netflix.loadbalancer.WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用轮询的策略,等统计信息足够会切换到自身规则。
  6. com.netflix.loadbalancer.BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量小的服务。
  7. com.netflix.loadbalancer.RetryRule 先按照轮询的策略获取服务,如果获取服务失败则在指定的时间内会进行重试,获取可用服务。

配置此消费者嗲用任何服务都用某种负载均衡策略

示例:这里设置的是随机策略 ,这样的话这个消费者调用所有的服务负载均衡策略都是随机策略。
启动类中添加,当然你也可以是新建一个类并添加上@Configuration注解。

/*** @description:往容器中方一个rule对象* 你访问任何一个提供者 都是这个算法* @author: wangwei* @date: 2023/7/31 8:49* @param: []* @return: com.netflix.loadbalancer.IRule**/@Beanpublic IRule myRule(){return new RandomRule();}}

访问不同的服务使用不同的算法规则

在yml文件中添加:

#访问不同的服务可以使用不同的算法规则
provider: #服务的应用名ribfatkunbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #算法的全限定类名

示例:

server:port: 8082spring:application:name: consumereureka:client:service-url:defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔#访问不同的服务可以使用不同的算法规则
provider: #服务的应用名ribfatkunbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #算法的全限定类名ribbon:eager-load:enabled: false #ribbon只有自己的话是不能做服务发现,需要借助eureka。如果为false表示懒加载,请求调用的时候开启。如果为true表示程序启动的时候开启eureka:enabled: truehttp: #我们使用ribbon用的是RestTemplate发请求。底层是java.net.HttpUrlConnection发的请求, 很方便但是不支持连接池client:  # 发送请求的工具有很多如:httpClient 它支持连接池,效率更好。如果你想该请求的工具,需要添加对应的依赖。enabled: falseokhttp:   #这个也是请求工具,移动端用的比较多, 轻量级请求enabled: false

总结

  1. 通过对Ribbon的理论和实践的学习,让我对Ribbon的理解不再停留知道的层面上,而是切切实实的实践过。
  2. 相对整体和系统的对Ribbon进行了了解和学习,并且和其他微服务组件进行了链接。

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

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

相关文章

数据结构--单链表OJ题

上文回顾---单链表 这章将来做一些链表的相关题目。 目录 1.移除链表元素 2.反转链表 3.链表的中间结点 4.链表中的倒数第k个结点 5.合并两个有序链表 6.链表分割 7.链表的回文结构 8.相交链表 9.环形链表 ​编辑 10.环形链表II ​编辑 ​编辑 1.移除链表元素 思…

后端进阶之路——浅谈Spring Security用户、角色、权限和访问规则(三)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

项目出bug,找不到bug,如何拉回之前的版本

1.用gitee如何拉取代码 本文为转载于「闪耀太阳a」的原创文章原文链接&#xff1a;https://blog.csdn.net/Gufang617/article/details/119929145 怎么从gitee上拉取代码 1.首先找到gitee上想要拉取得代码URL地址 点击复制这里的https地址 1 ps:&#xff08;另外一种方法&…

Source Insight和Keil中文乱码

1、问题原因 由于Source Insight和Keil中的中文编码方式的不同&#xff0c;导致Keil中添加的中文注释在Source Insight中乱码&#xff1b;在Source Insight中添加的中文注释在Keil中乱码。所以需要统一两者的编码方式。 Source Insight默认编码方式为UTF-8&#xff0c;Keil中一…

C++ | C++11新特性(上)

目录 前言 一、列表初始化 二、声明 1、auto 2、decltype 3、nullptr 三、STL容器的变化 四、右值引用与移动语义 1、左值与左值引用 2、右值与右值引用 3、右值引用与左值引用的比较 4、右值引用的场景及意义 &#xff08;1&#xff09;做参数 &#xff08;2&a…

Java数据流、对象流

文章目录 数据流与对象流说明对象流API认识对象序列化机制如何实现序列化机制反序列化失败问题 数据流与对象流说明 如果需要将内存中定义的变量&#xff08;包括基本数据类型或引用数据类型&#xff09;保存在文件中&#xff0c;那怎么办呢&#xff1f; int age 300; char …

Javascript 数据结构[入门]

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

新手注意事项-visual studio 来实现别踩白块儿

自己之前为了熟悉easyx练习过一个简单的项目&#xff0c;别踩白块儿&#xff0c;链接在这里&#xff0c;别踩白块儿&#xff0c;当时比较稚嫩&#xff0c;很多东西都不会&#xff0c;可以说是只知道最基本的语法&#xff0c;头文件都不知道&#xff0c;一个一个查资料弄懂的&am…

FreeRTOS(vTaskList与vTaskGetRunTimeStats)

目录 1、Cube配置 ①配置SYS ②配置TIM3 ③配置USART2 ④配置FreeRTOS ⑤配置中断优先级 2、代码添加改动 ①在main函数合适位置开启TIM3中断 ②修改HAL_TIM_PeriodElapsedCallback函数 ③完善两个相关函数 ④vTaskList与vTaskGetRunTimeStats的使用 vTaskList&#xff…

c语言每日一练(2)

前言&#xff1a; 每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;暑假时三天之内必有一更&#xff0c;到了开学之后&#xff0c;将看学业情…

VUE框架:vue2转vue3全面细节总结(3)路由组件传参

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

嵌入式开发学习(STC51-18-LCD液晶显示)

内容 在LCD1602液晶上显示字符信息&#xff1b; LCD1602介绍 简介 1602液晶也叫1602字符型液晶&#xff0c;它能显示2行字符信息&#xff0c;每行又能显示16个字符&#xff1b; 它是一种专门用来显示字母、数字、符号的点阵型液晶模块&#xff1b; 它是由若干个5x7或者5x…