Ribbon客户端负载均衡策略测试及其改进
文章目录
- 一、目的概述
- 二、验证步骤
- 1、源码下载
- 2、导入IDE
- 3、运行前修改配置
- 4、策略说明
- 5、修改策略
- 三、最终结论
- 四、改进措施
- 1. 思路分析
- 2. 核心代码
- 3. 测试页面
一、目的概述
为了验证Ribbon客户端负载均衡策略在负载节点失效的情况下,是否具有故障转移的功能,进行了以下代码验证!
二、验证步骤
1、源码下载
git clone https://gitee.com/00fly/microservice-all-in-one.git
https://gitee.com/00fly/microservice-all-in-one/tree/master/ribbon-demo-simple
2、导入IDE

3、运行前修改配置
根据调用关系,我们需要启动2个user服务,为了方便调试我们这边分别启动8081、8082端口的user服务,并在movie模块中,设置负载节点地址为:127.0.0.1:8081,127.0.0.1:8082
以eclipse为例简要说明
查看环境配置

打开Dashboard,选择Duplicate config

选择open Config

选择Profile设置为dev

全部启动

docker部署相对简单,编排文件为
https://gitee.com/00fly/microservice-all-in-one/blob/master/ribbon-demo-simple/docker/docker-compose.yml
version: '3.8'
services:#负载均衡节点ribbon-user-simple-0:image: registry.cn-shanghai.aliyuncs.com/00fly/ribbon-user-simple:0.0.1container_name: ribbon-user-simple-0deploy:resources:limits:cpus: '1'memory: 200Mreservations:memory: 180Mrestart: on-failurelogging:driver: json-fileoptions:max-size: 5mmax-file: '1'#负载均衡节点ribbon-user-simple-1:image: registry.cn-shanghai.aliyuncs.com/00fly/ribbon-user-simple:0.0.1container_name: ribbon-user-simple-1deploy:resources:limits:cpus: '1'memory: 200Mreservations:memory: 180Mrestart: on-failurelogging:driver: json-fileoptions:max-size: 5mmax-file: '1'#调用方ribbon-movie-simple:image: registry.cn-shanghai.aliyuncs.com/00fly/ribbon-movie-simple:0.0.1container_name: ribbon-movie-simpledeploy:resources:limits:cpus: '1'memory: 200Mreservations:memory: 180Mports:- 8090:8082environment:USER_SERVERS: ribbon-user-simple-0:8081,ribbon-user-simple-1:8081restart: on-failurelogging:driver: json-fileoptions:max-size: 5mmax-file: '1'
4、策略说明
- RandomRule 实现从服务实例清单中随机选择一个服务实例的功能。
- RoundRobinRule 实现了按照线性轮询的方式依次选择每个服务实例的功能。
- RetryRule 实现了一个具备重试机制的实例选择功能。
- WeightedResponseTimeRule是对 RoundRobinRule 的拓展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例。
- ClientConfigEnableRoundRobinRule 通过继承该策略,在子类中做一些高级策略时有可能会存在一些无法实施的情况,那么就可以用父类的实现作为备选(线性轮询机制)。
- BestAvailableRule 通过遍历负载均衡器中维护的所有服务实例,会过滤掉故障的实例,并找出并发请求数最小的一个,所以该策略的特性是可选出最空闲的实例。
- PredicateBasedRule 先通过子类实现中的 Predicate 逻辑来过滤一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个。
- AvailabilityFilteringRule 通过线性抽样的方式直接尝试寻找可用且较空闲的实例来使用。
- ZoneAvoidanceRule 根据负载情况选择可用区
5、修改策略
修改这边的负载均衡策略
打开页面

停止8081或8082端口服务,重新调试,返回结果如下:

三、最终结论
RandomRule、RoundRobinRule 策略不具备故障转移能力
RetryRule、WeightedResponseTimeRule等虽然具有故障转移,但是故障转移的时间太长,并且故障恢复后,重新选中该恢复的节点所需时间也较长。
各种策略的表现。大家可以自行研究测试。
四、改进措施
1. 思路分析
采用多线程,多个节点同时检测,返回最快响应的节点采用多线程,定义超时时间,返回超时时间之内有响应的节点, 后续根据规则选择1个节点
2. 核心代码
NodeController.java
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;import com.itmuch.cloud.study.user.entity.User;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;@Slf4j
@Api(tags = "负载均衡节点")
@RestController
@RequestMapping("/node")
public class NodeController
{@Autowiredprivate WebClient webClient;@Value("${microservice-ribbon-user.ribbon.listOfServers}")private List<String> listOfServers;private ExecutorService executorService = Executors.newFixedThreadPool(10);@ApiOperation("查询用户")@GetMapping("/user/{id}")public List<User> findById(@PathVariable Long id)throws InterruptedException{// WebClient支持异步List<User> users = new CopyOnWriteArrayList<User>();listOfServers.stream().forEach(hostWithPort -> webClient.get().uri(String.format("http://%s/%s", hostWithPort, id))// URI.acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).subscribe(resp -> users.add(resp)));int index = 0;while (users.isEmpty() && (index++) < 100){TimeUnit.MILLISECONDS.sleep(10);log.info("index:{}, waitting......", index);}if (users.isEmpty()){throw new RuntimeException("查询超时,无返回值");}return users;}@ApiOperation("查询用户 by execute")@GetMapping("/v0/user/{id}")public List<User> findByExecute(@PathVariable Long id)throws InterruptedException{// List<User> users = new ArrayList<User>();// TODO ArrayList users一定概率有null值// 原因:通过new ArrayList<>()初始化的大小是0,首次插入触发扩容,并发可能导致出现null值List<User> users = new CopyOnWriteArrayList<User>();listOfServers.stream().forEach(hostWithPort -> executorService.execute(() -> webClient.get().uri(String.format("http://%s/%s", hostWithPort, id))// URI.acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).subscribe(resp -> users.add(resp))));int index = 0;while (users.isEmpty() && (index++) < 100){TimeUnit.MILLISECONDS.sleep(10);log.info("index:{}, waitting......", index);}if (users.isEmpty()){throw new RuntimeException("查询超时,无返回值");}return users;}@ApiOperation("查询用户 by submit")@GetMapping("/v1/user/{id}")public List<User> findBySubmit(@PathVariable Long id)throws InterruptedException{List<User> users = new CopyOnWriteArrayList<User>();listOfServers.stream().forEach(hostWithPort -> executorService.submit(() -> webClient.get().uri(String.format("http://%s/%s", hostWithPort, id))// URI.acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).subscribe(resp -> users.add(resp)), users));int index = 0;while (users.isEmpty() && (index++) < 100){TimeUnit.MILLISECONDS.sleep(10);log.info("index:{}, waitting......", index);}if (users.isEmpty()){throw new RuntimeException("查询超时,无返回值");}return users;}@ApiOperation("查询用户 by invokeAny")@GetMapping("/v2/user/{id}")public User findByInvokeAny(@PathVariable Long id)throws InterruptedException, ExecutionException, TimeoutException{return executorService.invokeAny(listOfServers.stream().map(hostWithPort -> new Callable<User>(){@Overridepublic User call(){Mono<User> mono = webClient.get().uri(String.format("http://%s/%s", hostWithPort, id))// URI.acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class);return mono.block();}}).collect(Collectors.toList()), 1000, TimeUnit.MILLISECONDS);}@ApiOperation("查询用户 by invokeAll")@GetMapping("/v3/user/{id}")public List<User> findByInvokeAll(@PathVariable Long id)throws InterruptedException{List<Future<User>> futures = executorService.invokeAll(listOfServers.stream().map(hostWithPort -> new Callable<User>(){@Overridepublic User call(){Mono<User> mono = webClient.get().uri(String.format("http://%s/%s", hostWithPort, id))// URI.acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class);return mono.block();}}).collect(Collectors.toList()), 1000, TimeUnit.MILLISECONDS);List<User> users = new ArrayList<User>();for (Future<User> future : futures){try{users.add(future.get());}catch (Exception e){log.error(e.getMessage(), e);}}return users;}
}
3. 测试页面

有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!
-over-
相关文章:
Ribbon客户端负载均衡策略测试及其改进
文章目录 一、目的概述二、验证步骤1、源码下载2、导入IDE3、运行前修改配置4、策略说明5、修改策略 三、最终结论四、改进措施1. 思路分析2. 核心代码3. 测试页面 一、目的概述 为了验证Ribbon客户端负载均衡策略在负载节点失效的情况下,是否具有故障转移的功能&a…...
linux网络编程5——Posix API和网络协议栈,使用TCP实现P2P通信
文章目录 Posix API和网络协议栈,使用TCP实现P2P通信1. socket()2. bind()3. listen()4. connect()5. accept()6. read()/write(), recv()/send()7. 内核tcp数据传输7.1 TCP流量控制7.2 TCP拥塞控制——慢启动/拥塞避免/快速恢复/快速重传 8. shutdown()9. close()9…...
低代码平台中的功能驱动开发:模块化与领域设计
在现代软件开发中,尤其是在低代码平台的背景下,清晰地定义功能和模块是成功的关键。功能驱动开发强调功能的优先性,模块化设计则确保系统的可维护性和可扩展性。本文将探讨如何在低代码平台中有效地将功能与模块结合起来,形成一个…...
HTTP和HTTPS基本概念,主要区别,应用场景
HTTP和 HTTPS是用于在网络中传输数据的协议,虽然它们的功能类似,但在安全性上存在显著差异。 1. HTTP 的基本概念 定义:HTTP 是一种无状态的、面向请求-响应的协议,用于客户端(如浏览器)和服务器之间传输…...
node.js使用Sequelize ORM操作数据库
一、什么是ORM ORM是在数据库和编程语言之间建立一种映射关系,这样可以让我们有非常简单的代码,来实现各种数据库的操作。 例如:使用mysql去查找表(表名称为Articles) SELECT * FROM Articles;但是我们使用ORM的话&…...
STM32-Modbus协议(一文通)
Modbus协议原理 RT-Thread官网开源modbus RT-Thread官方提供 FreeModbus开源。 野火有移植的例程。 QT经常用 libModbus库。 Modbus是什么? Modbus协议,从字面理解它包括Mod和Bus两部分,首先它是一种bus,即总线协议,和…...
100. 不同方向的投影视图
本节课给大家讲解,通过UI按钮界面交互改变threejs相机的观察视角。 x轴方向观察 // 通过UI按钮改变相机观察角度 document.getElementById(x).addEventListener(click, function () {camera.position.set(500, 0, 0); //x轴方向观察camera.lookAt(0, 0, 0); //重新…...
Appium中的api(三)
目录 Appium中的api(三) 1.输入和清空内容 1--输入内容 2--清空内容 2.获取文本内容 3.获取文本位置 4.获取文本的大小(即获取控件的宽和高) 5.滑动api 6.拖拽api 7.如何获取手机分辨率 8.如何截图 9.模拟按键事件api 10.操作通知栏 案例:App自动化模拟 …...
踩坑:关于使用ceph pg repair引发的业务阻塞
概述 在某次故障回溯中,发现引发集群故障,slow io,pg stuck的罪魁祸首竟是做了一次ceph pg repair $pgid。然而ceph pg repair作为使用频率极高的,用来修复pg不一致的常用手段,平时可能很少注意其使用规范和可能带来的…...
瞬间升级!电子文档华丽变身在线题库,效率翻倍✨
👋嘿小伙伴们,有个超赞的秘籍要告诉你们——土著刷题能将你的电子文档一键变身在线题库!😉 你还没发现这个宝藏功能吗?快来瞧瞧! 🌟是不是常被一堆电子版的学习资料搞得头昏脑涨,学习…...
如何动态改变本地的ip
在当今数字化时代,网络连接已成为我们日常生活和工作中不可或缺的一部分。无论是出于隐私保护、突破地域限制,还是为了测试和优化网络应用,动态改变本地IP地址的需求日益增多。本文将详细介绍如何安全、有效地实现这一目标,旨在帮…...
Spring Boot框架在中小企业设备管理中的创新应用
4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式,是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示: 图4-1系统工作原理…...
Ceph入门到精通-Osd db扩容
ceph-bluestore-tool 是一个在 BlueStore 实例上执行低级管理操作的实用程序。 以下命令可用于 ceph-bluestore-tool 语法 ceph-bluestore-tool COMMAND [ --dev DEVICE … ] [ -i OSD_ID ] [ --path OSD_PATH ] [ --out-dir DIR ] [ --log-file | -l filename ] [ --deep ]c…...
windows msvc2017 x64编译AWS SDK CPP库
在本文中,我们将介绍如何编译AWS SDK C库,以便在您的项目中使用。AWS SDK C库提供了与Amazon Web Services交互的接口,允许您在C应用程序中使用AWS服务。 一、准备工作 在开始编译AWS SDK C库之前,请确保您的系统已经安装了以下…...
铜业机器人剥片 - SNK施努卡
SNK施努卡有色行业电解车间铜业机器人剥片 铜业机器人剥片技术是针对传统人工剥片效率低下、工作环境恶劣及生产质量不稳定的痛点而发展起来的自动化解决方案。 面临人工剥片的诸多挑战,包括低效率、工作环境差、人员流动大以及产品质量控制不精确等问题。 人工剥片…...
非接触式竖向位移、水平位移视频实时在线监测的设备分类及选型
前言 视觉是人工智能正在快速发展的一个分支,简单说来,机器视觉就是用机器代替人眼来做测量和判断。在结构健康自动化监测方面,机器视觉采用光学图像结合智能算法和物联网技术,利用先进的智能靶标识别及亚像素处理等技术ÿ…...
Svelte 5 正式发布:新一代前端框架!
10 月 22 日,Svelte 5 正式发布!该版本带来的更新主要包括: 重写框架:Svelte 5 是从头开始重写的,使得应用更快、更小、更可靠,并且代码更一致和符合习惯。 向后兼容:Svelte 5 几乎完全向后兼容…...
85.【C语言】数据结构之顺序表的中间插入和删除及遍历查找
目录 3.操作顺序表 1.分析中间插入函数 函数的参数 代码示例 图片分析 main.c部分改为 在SeqList.h添加SLInsert函数的声明 运行结果 2.分析中间删除函数 函数的参数 代码示例 图片分析 main.c部分改为 在SeqList.h添加SLErase函数的声明 运行结果 承接84.【C语…...
触觉智能Purple Pi OH鸿蒙开发板成功适配OpenHarmony5.0 Release,开启新征程!
10月22日,触觉智能Purple Pi OH鸿蒙开发板迎来了重大系统版本升级,成功适配OpenHarmony5.0 Release,为嵌入式开发者和科技爱好者们带来了全新的机遇与挑战! 触觉智能 Purple Pi OH 开发板一直以来都以其高品质和超高性价比而著称。…...
分布式解决方案---分布式ID
目录 是什么 特点 全局唯一 高并发 高可用 怎么做 实现方案 是什么 分布式ID是指在分布式系统中生成的唯一标识符。由于分布式系统的特点,多个节点可能会同时生成ID,因此需要确保每个ID在整个系统中是唯一的。 重点就是唯一性!&#x…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
UE5 音效系统
一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类,将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix,将上述三个类翻入其中,通过它管理每个音乐…...
