SpringCloud Ribbon 负载均衡服务调用
一、前言
接下来是开展一系列的 SpringCloud 的学习之旅,从传统的模块之间调用,一步步的升级为 SpringCloud 模块之间的调用,此篇文章为第三篇,即介绍 Ribbon 负载均衡服务调用
二、概述
2.1 Ribbon 是什么
Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具。
简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出 Load Balancer(简称 LB)后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用 Ribbon 实现自定义的负载均衡算法。
2.2 Ribbon 资料
可以进入官网,查看该工具的使用方式,github 源码的地址在这,不过到目前为止, Ribbon 也进入了维护模式,如下图
2.3 Ribbon 用途
Ribbon 可以实现负载均衡(Load Balance)的功能。
2.3.1 负载均衡是什么
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的 HA(高可用)。常见的负载均衡有软件 Nginx,LVS,硬件 F5 等。
2.3.2 Ribbon 和 Nginx 区别
Ribbon 本地负载均衡客户端 和 Nginx 服务端负载均衡有什么区别呢?
Nginx 是服务器负载均衡,客户端所有请求都会交给 nginx,然后由 nginx 实现转发请求。即负载均衡是由服务端实现的。
Ribbon 本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到 JVM 本地,从而在本地实现 RPC 远程服务调用技术。
2.3.3 总结
前面第二篇文章我们通过配置订单模块的负载均衡,轮询的去访问我们的两个支付模块 8001 和 8002 ,采用的技术就是 负载均衡+ RestTemplate 调用。
三、Ribbon 负载均衡演示
3.1 架构说明
Ribbon 在工作时分成两步,第一步先选择 EurekaServer,它优先选择在同一个区域内负载较少的 server。第二步再根据用户指定的策略,在从 server 取到的服务注册列表中选择一个地址。
Ribbon 提供了多种策略:比如轮询、随机和根据响应时间加权。
3.2 pom 说明
之前在 cloud-consumer-order80 订单模块我们并没有引入 Ribbon 的依赖也可以使用它,那是因为 spring-cloud-starter-netflix-eureka-client 自带了 spring-cloud-starter-ribbon 引用,如下图:
3.3 RestTemplate
在没有使用 OpenFeign 组件之前,我们还是使用 RestTemplate 来进行远程服务的调用,其主要使用的方法就是 getForObject/getForEntity、postForObject/postForEntity 如下所示:
@RestController
@Slf4j
public class OrderController {@Resourceprivate RestTemplate restTemplate;// public static final String PaymentSrv_URL = "http://localhost:8001";public static final String PAYMENT_SRV = "http://CLOUD-PAYMENT-SERVICE";@GetMapping("/consumer/payment/create")public CommonResult create(Payment payment){// 客户端用浏览器是get请求,但是底层实质发送post调用服务端8001// return restTemplate.postForObject(PAYMENT_SRV+"/payment/create",payment,CommonResult.class);return restTemplate.postForEntity(PAYMENT_SRV+"/payment/create",payment,CommonResult.class).getBody();}// 返回对象为响应体中数据转化成的对象,基本上可以理解为Json@GetMapping("/consumer/payment/get/{id}")public CommonResult getPayment(@PathVariable Long id){return restTemplate.getForObject(PAYMENT_SRV + "/payment/get/"+id, CommonResult.class, id);}// 返回对象为 ResponseEntity 对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等@GetMapping("/consumer/payment/getForEntity/{id}")public CommonResult getPayment2(@PathVariable Long id){ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_SRV + "/payment/get/" + id, CommonResult.class, id);if(entity.getStatusCode().is2xxSuccessful()){return entity.getBody();}else{return new CommonResult(444,"操作失败");}}}
四、Ribbon 核心组件 IRule
4.1 默认的负载均衡算法
IRule 是负载均衡顶级的父接口,它会根据特定的算法从服务列表中选取一个要访问的服务,它的实现类,它的类图如下所示:
IRule 接口现有的实现类,即默认存在的负载均衡策略如下:
1、com.netflix.loadbalancer.RoundRobinRule,轮询(默认)
2、com.netflix.loadbalancer.RandomRule,随机
3、com.netflix.loadbalancer.RetryRule,先按照 RoundRobinRule 的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。
4、WeightedResponseTimeRule,对 RoundRobinRule 的扩展,响应速度越快的实例选择权重越大,越容易被选择。
5、BestAvailableRule,会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
6、AvailabilityFilteringRule,先过滤掉故障实例,再选择并发较小的实例
7、ZoneAvoidanceRule,默认规则,复合判断 server 所在区域的性能和 server 的可用性选择服务器。
4.2 替换默认负载均衡算法
4.2.1 配置细节
我们需要新建一个自定义配置类来替换默认的负载均衡算法,但是官方文档明确给出了警告,这个自定义配置类不能放在 @ComponentScan 所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的 Ribbon 客户端所共享,达不到特殊化定制的目的了。
我们在 cloud-consumer-order80 模块上进行配置,现在的项目结构如下所示:
我们如果想要自定义一个配置类,就需要重新创建一个包,且这个包不被 Spring 扫描到,如下图:
4.2.2 创建配置类
在 myrule 包下,创建自定义配置类 MySelfRule,代码如下所示:
@Configuration
public class MySelfRule {@Beanpublic IRule myRule(){// 定义一个随机类型的负载均衡算法return new RandomRule();}
}
4.2.3 修改主启动类
在主启动类上,添加注解,并指定负载均衡的类型和服务的名称,如下:
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration= MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}
4.2.4 测试
分别启动 cloud-eureka-server7001、cloud-eureka-server7002、cloud-provider-payment8001、cloud-provider-payment8002 和 cloud-consumer-order80 模块,然后不断的刷新请求地址 http://localhost/consumer/payment/get/1,如下图:
五、Ribbon 负载均衡算法
5.1 原理
轮询负载均衡算法:rest 接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后 rest 接口计数从 1 开始。
以 8081 和 8082 组合成集群为例,一共两台机器,集群总数量为 2 ,按照轮询的算法原理:
1、当总请求数为 1 时: 1 % 2 =1 对应下标位置为 1 ,则获得服务地址为 127.0.0.1:8001
2、当总请求数位 2 时: 2 % 2 =0 对应下标位置为 0 ,则获得服务地址为 127.0.0.1:8002
3、当总请求数位 3 时: 3 % 2 =1 对应下标位置为 1 ,则获得服务地址为 127.0.0.1:8001
4、 当总请求数位 4 时: 4 % 2 =0 对应下标位置为 0 ,则获得服务地址为 127.0.0.1:8002
以此类推。
5.2 手写负载均衡算法
接下来我们手写一个轮询类型的负载均衡算法。
首先在 cloud-provider-payment8001 和 cloud-provider-payment8002 模块的 PaymentController 类中添加如下的方法用于后续的测试:
@GetMapping(value = "/payment/lb")
public String getPaymentLB()
{return serverPort;
}
然后把 cloud-consumer-order80 模块的 ApplicationContextConfig 类的负载均衡的注解注释掉,如下:
@Configuration
public class ApplicationContextConfig {@Bean//使用@LoadBalanced注解赋予RestTemplate负载均衡的能力// @LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
在 cloud-consumer-order80 模块中创建一个接口和实现类,用来实现轮询的负载均衡,如下:
package com.springcloud.lb;import org.springframework.cloud.client.ServiceInstance;import java.util.List;public interface LoadBalancer {// 从服务器集群中选择一台来处理请求ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
package com.springcloud.lb;import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;@Component
public class MyLB implements LoadBalancer{// 创建一个原子类来记录服务调用的次数private AtomicInteger atomicInteger = new AtomicInteger(0);public final int getAndIncrement(){int current;int next;do{// 获取当前的调用次数的值current = this.atomicInteger.get();// 获取下一次调用次数的值,若值大于 Integer 的最大值则重新开启计数next = current > 2147483647 ? 0 : current +1;// 自旋锁,current 为当前值,next 为期望值,如果不满足这个条件则一直自旋,使用 CAS 保证线程安全}while(!this.atomicInteger.compareAndSet(current,next));System.out.println("***********next 第几次调用:"+next);return next;}@Overridepublic ServiceInstance instances(List<ServiceInstance> serviceInstances) {// 用当前调用次数的下标除以集群的数量,然后取余数int index = getAndIncrement() % serviceInstances.size();// 最终确定由集群的哪台机器处理请求return serviceInstances.get(index);}
}
修改 cloud-consumer-order80 模块的 OrderController 类的代码,使其调用方法时采用我们指定的负载均衡的策略,代码如下:
@RestController
@Slf4j
public class OrderController {@Resourceprivate RestTemplate restTemplate;// public static final String PaymentSrv_URL = "http://localhost:8001";public static final String PAYMENT_SRV = "http://CLOUD-PAYMENT-SERVICE";@GetMapping("/consumer/payment/create")public CommonResult create(Payment payment){// 客户端用浏览器是get请求,但是底层实质发送post调用服务端8001return restTemplate.postForObject(PAYMENT_SRV+"/payment/create",payment,CommonResult.class);}// 返回对象为响应体中数据转化成的对象,基本上可以理解为Json@GetMapping("/consumer/payment/get/{id}")public CommonResult getPayment(@PathVariable Long id){return restTemplate.getForObject(PAYMENT_SRV + "/payment/get/"+id, CommonResult.class, id);}@Resourceprivate LoadBalancer loadBalancer;@Resourceprivate DiscoveryClient discoveryClient;@GetMapping("/consumer/payment/lb")public String getPaymentLB(){// 获取集群上所有可用的节点List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");if(instances == null || instances.size()<=0) {return null;}// 选择具体由哪台机器干活ServiceInstance serviceInstance = loadBalancer.instances(instances);URI uri = serviceInstance.getUri();// 干活return restTemplate.getForObject(uri+"/payment/lb",String.class);}
}
接下来进行测试,启动各个模块,在浏览器输入 http://localhost/consumer/payment/lb,如下图,可以看到刷新一次浏览器,界面显示的都会发生有规则的变化。
控制台的后台打印内容如下:
相关文章:

SpringCloud Ribbon 负载均衡服务调用
一、前言 接下来是开展一系列的 SpringCloud 的学习之旅,从传统的模块之间调用,一步步的升级为 SpringCloud 模块之间的调用,此篇文章为第三篇,即介绍 Ribbon 负载均衡服务调用 二、概述 2.1 Ribbon 是什么 Spring Cloud Ribbon…...

物联网在智慧城市建设中的关键作用:连接、感知、智能响应
一、引言 随着信息技术的飞速发展,物联网(IoT)技术已经渗透到我们生活的方方面面,特别是在智慧城市建设中发挥着至关重要的作用。智慧城市是指通过运用先进的信息和通信技术,实现城市基础设施、公共服务、交通管理、环…...

安卓7原生相机切到视频崩溃
目录 1、查看日志 2、分析日志、提取重点 3、寻找解决方法 author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 daisy.skye_嵌入式,Linux,Qt-CSDN博客daisy.skye擅长嵌入式,Linux,Qt,等方面的知识https://blog.csdn.net/qq_40715266?typeblog 1、查看日志 由于安…...

构建信息蓝图:概念模型与E-R图的技术解析
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua,在这里我会分享我的知识和经验。&#x…...

docker拉取镜像失败的解决方案大全
更换国内源 创建或修改 /etc/docker/daemon.json 文件,修改: {"registry-mirrors" : ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn","https:…...

Axure Cloud如何给每个原型配置私有域名
需求 在原型发布之后,自动给原型生成一个独立访问的域名,类似http://u591bi.axshare.bushrose.cn,应该如何配置呢? 准备事项 已备案域名 如何备案?阿里云备案流程 已安装部署Axure Cloud 如何安装部署,请…...

语音模块学习——LSYT201B模组(实际操作篇)
目录 一、定制词条 二、直接用串口通信 三、使用单片机通信 理论篇在这,依旧是深圳雷龙发展的语音模块。 http://t.csdnimg.cn/2SzJL 一、定制词条 因为我想后面加到我的毕设上加个语音模块,所以定制的词条都是和芯测相关的。 动作词条播报串口输…...

Android应用界面
概述:由于学校原因,估计会考,曹某人就浅学一下。 目录 View概念 创建和使用布局文件 相对布局 线性布局 水平线性布局 垂直线性布局 表格布局 帧布局 扁平化布局 Android控件详解 AdapterView及其子类 View概念 安卓中的View是所…...

生活的色彩--爱摸鱼的美工(17)
题记 生活不如意事十之八九, 恶人成佛只需放下屠刀,善人想要成佛却要经理九九八十一难。而且历经磨难成佛的几率也很小,因为名额有限。 天地不仁以万物为刍狗! 小美工记录生活,记录绘画演变过程的一天。 厨房 食…...

【YOLO v5 v7 v8 v9小目标改进】AFPN 渐进式特征金字塔网络:解决多尺度特征融合中,信息在传递过程丢失
AFPN 渐进式特征金字塔网络:解决多尺度特征融合中,信息在传递过程丢失 提出背景AFPN 多尺度特征金字塔 非邻近层次的直接特征融合 自适应空间融合操作 小目标涨点YOLO v5 魔改YOLO v7 魔改YOLO v8 魔改YOLO v9 魔改 提出背景 论文:https:…...

问题解决 | vscode无法连接服务器而ssh和sftp可以
解决步骤 进入家目录删除.vscode-server rm -rf .vscode-server 然后再次用vscode连接服务器时,会重新安装,这时可能报出一些缺少依赖的错 需要联系管理员安装相关依赖,比如 sudo apt-get install libstdc6 至此问题解决...

Git 远程操作
1.分布式版本控制系统 我们目前所说的所有内容(工作区,暂存区,版本库等等),都是在本地!也就是在你的笔记本或者计算机上。而我们的 Git 其实是分布式版本控制系统!什么意思呢 可以简单理解为&am…...

Windows C++ 实现远程虚拟打印机(远程共享打印机)
编译错误已经修改完后的工程修改后的下载地址 https://download.csdn.net/download/2403_83063732/88928550 1、下载clawpdf(0.8.7版本) https://github.com/clawsoftware/clawPDF 2、打开clawpdf工程开始编译C#工程,出现如下错误…...

【jvm】java对象占用内存问题深入解析
一个Java对象占用多大内存-CSDN博客 关于Object o new Object()追魂九连问(个人学习笔记) - 知乎JVM(Java虚拟机)-史上最全、最详细JVM笔记-CSDN博客...

金现代产品方案部部长王宁,将出席“ISIG-低代码/零代码技术与应用发展峰会”
3月16日,第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导,企智未来科技(LowCode低码时代、RPA中国、AIGC开放社区)主办。大会旨在聚合每一位产业成员的力量,深入探索低…...

数据结构——lesson7二叉树 堆的介绍与实现
前言💞💞 啦啦啦~这里是土土数据结构学习笔记🥳🥳 💥个人主页:大耳朵土土垚的博客 💥 所属专栏:数据结构学习笔记 💥对于数据结构顺序表链表有疑问的都可以在上面数据结…...

阿里云DSW做AI绘画时的显卡选择A10?V100?
V100是Volta架构,A10是Ampere架构,架构上讲A10先进点,其实只是制程区别,用起来没区别。 V100是HBM的内存读取,带宽大,但是DDR5的。 二块卡都是全精度为主的算力卡,半精度优势不明显。 需要用…...

MySQL安装使用(mac)
目录 一、下载MySQL 二、环境变量 三、启动 MySql 四、初始化密码设置 一、下载MySQL 打开 MySql 官方下载页面 我是macOS12,所以选择了8.0.30 下载完成之后,打开安装,一直下一步安装完成,在最后安装完成时,会弹出…...

Qt控制台项目也能使用opencv的imshow来显示摄像头视频
创建一个Qt控制台项目,目的是实现在控制台打开摄像头视频。由于windows平台是支持GUI(图形用户界面)功能,所以在windows环境下是可以打开的,但是linux环境下,由于不支持GUI功能,而是支持wayland,…...

前端缓存使用规范
一、Cookie使用规范 cookie的存储空间非常有限且会携带在请求头中会浪费不必要的流量,如果仅仅是为存储数据,可以采用其他替代方案,例如 webStorage,非必要不使用cookie。 1、使用方法 注意:过期时间时需转换成UTC格…...

Linux rmmod命令教程:如何卸载内核模块(附实例详解和注意事项)
Linux rmmod命令介绍 rmmod(全称:remove module)用于从Linux内核中卸载已加载的内核模块。它允许您在运行时移除不再需要的模块,以释放系统资源或更改内核配置。 Linux rmmod命令适用的Linux版本 rmmod在大多数Linux发行版中通…...

中国气象要素年度空间插值数据集
摘要 中国气象要素年度空间插值数据集是地理遥感生态网平台基于全国2400多个站点的气象要素站点日观测数据,在计算各气象要素年值的基础上,基于Anuspl插值软件生成1960-2021年各年度蒸发量、地温、降水量、气压、相对湿度、日照时数 、气温、风速8个气象…...

链表习题-力扣oj (附加思路版)
LCR 140. 训练计划 IIhttps://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号,请查找并返回倒数第 cnt 个训练项目编号。 思路:双指针,快指针先走cnt…...

HNU-计算机网络-甘晴void学习感悟
前言 计算机网络其实我没太学懂, 仅从应试来说,考试成绩也不太好。 这也是为什么一直没有更新这一学科的学习感悟。 大三下还是有点闲,一周三天小长假,闲来无事还是给写了。 教材使用这本: 总领 期中考试 30% 期…...

混合输入矩阵乘法的性能优化
作者 | Manish Gupta OneFlow编译 翻译|宛子琳、杨婷 AI驱动的技术正逐渐融入人们日常生活的各个角落,有望提高人们获取知识的能力,并提升整体生产效率。语言大模型(LLM)正是这些应用的核心。LLM对内存的需求很高&…...

安卓Kotlin面试题 41-50
41、如何在 Kotlin 中实现 Builder 模式?首先,在大多数情况下,您不需要在 Kotlin 中使用构建器,因为我们有默认和命名参数,但如果您需要使用://add private constructor if necessary class Car( val model: String?,val year: Int) { private constructor(build…...

portainer管理远程docker和docker-swarm集群
使用前请先安装docker和docker-compose,同时完成docker-swarm集群初始化 一、portainer-ce部署 部署portainer-ce实时管理本机docker,使用docker-compose一键拉起 docker-compose.yml version: 3 services:portainer:container_name: portainer#imag…...

分销商城微信小程序:用户粘性增强,促进复购率提升
在数字化浪潮的推动下,微信小程序作为一种轻便、高效的移动应用形式,正成为越来越多企业开展电商业务的重要平台。而分销商城微信小程序的出现,更是为企业带来了前所未有的机遇。通过分销商城微信小程序,企业不仅能够拓宽销售渠道…...

深度学习与机器学习:互补共进,共绘人工智能宏伟蓝图
在人工智能的广阔天地中,深度学习与机器学习如同两支强大的队伍,各自闪耀着独特的光芒,却又携手共进,共同书写着智能的辉煌篇章。尽管深度学习是机器学习的一个分支,但它们在模型构建、特征提取以及应用场景等多个方面…...

Vue.js 实用技巧:深入理解 Vue.mixin
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...