如何一步步优化负载均衡策略

发展到一定阶段后,Web 应用程序就会增长到单服务器部署无法承受的地步。这时候企业要么提升可用性,要么提升可扩展性,甚至两者兼而有之。为此,他们会将应用程序部署在多台服务器上,并在服务器之前使用负载均衡器来分配传入的请求。大公司可能需要数千台运行其 Web 应用程序的服务器来处理负载。

在这篇文章中,我们将重点关注单个负载均衡器将 HTTP 请求分发到一组服务器的各种可行方式。我们将从底层开始,逐步引出现代负载均衡算法。

一、问题可视化

我们先从头开始:单个负载均衡器将请求发送到单台服务器,请求以每秒 1 个请求(RPS)的速率发送,并且每个请求在服务器处理时都会逐渐缩小。对于很多网站来说,这种设置挺好用。现代服务器性能强大,可以处理大量请求。但是当它们的性能跟不上时会发生什么事情?

从上面的模拟中我们可以看到,3RPS 的速率导致一些请求被丢弃了。如果在处理一个请求时,另一个请求到达了服务器,服务器将丢弃后者。这将导致向用户显示的错误,这是我们要避免的事情。我们可以将另一台服务器添加到负载均衡器来解决这个问题。

现在不再有丢弃的请求了!我们的负载均衡器在这里起到了作用,依次向每台服务器发送请求,这称为“循环法”负载均衡。它是最简单的负载均衡形式之一,当你的服务器都同样强大并且你的请求都同样昂贵时,这个机制很合适。

二、当循环法不好用的时候

在现实世界中,服务器同样强大而请求同样昂贵的情况很少见。即使你使用完全相同的服务器硬件,它们的性能也可能不同。应用程序可能必须为许多不同类型的请求提供服务,并且这些请求可能具有不同的性能特征。

我们看看当我们改变请求成本时会发生什么事情。在以下模拟中,请求的成本并不相同。你可以看到一些请求比其他请求花费了更长的时间。

虽然大多数请求都得到了成功处理,但我们确实放弃了其中一些请求。缓解这种情况的方法之一是引入一个“请求队列”。

请求队列帮助我们应对不确定性,但这是一种权衡。我们将丢弃更少的请求,但代价是某些请求具有更高的延迟。如果你观看上面的模拟足够长的时间,你可能会注意到请求的颜色发生了微妙的变化。请求没有被送达的时间越长,它们的颜色变化的就越多。你还会注意到,由于请求成本差异,服务器开始表现出不均衡情况。队列会在运气不好的,必须连续服务多个昂贵请求的服务器上备份下来。如果队列已满,我们将丢弃请求。

上述情况同样适用于性能不一样的服务器组。在下一个模拟中,我们还改变了每台服务器的性能,在视觉上用较深的灰色阴影表示。

服务器被赋予一个随机的性能值,但很可能有些服务器的性能低于其他服务器,并且它们很快就会开始丢弃请求。与此同时,性能更强大的服务器大部分时间都处于闲置状态。这个场景展示了循环法的主要弱点:方差。

然而,尽管存在缺陷,循环法仍然是 nginx 的默认 HTTP 负载均衡方法。

三、改进循环法

我们可以改进循环法来更好地应对方差。有一种称为“加权循环法”的算法,其中用一个权重来标记每台服务器,该权重决定了向每台服务器发送多少请求。

在这个模拟中,我们使用每台服务器的已知性能值作为其权重,并在循环遍历它们时向更强大的服务器提供更多请求。

虽然这种机制能比普通循环法更好地处理服务器性能的差异,但我们仍然需要应对请求方差。在实践中,让人类手动设定权重的做法很快就会失败的。将服务器性能用某个数字来表示是很难的事情,并且需要对真实工作负载进行仔细的负载测试。实践中很少这样做,因此加权循环法的另一种变体会使用一个代理指标动态计算权重:它就是延迟。

按理说,如果一台服务器处理请求的性能是另一台服务器的 3 倍,那么它的速度可能就是另一台服务器的 3 倍,并且应该接收相当于另一台服务器 3 倍的请求数量。

这次我向每台服务器添加了文本,显示最后 3 个请求的平均延迟。然后我们根据延迟的相对差异决定是否向每台服务器发送 1、2 或 3 个请求。结果与初始的加权循环模拟非常相似,但无需预先指定每台服务器的权重。该算法还能适应服务器性能随时间的变化。这称为“动态加权循环法”。

我们来看看它如何处理服务器性能和请求成本都存在很大方差的复杂情况。以下模拟使用随机值,因此请随意刷新页面几次,查看它是否适应了新的情况。

四、循环法以外的选项

动态加权循环似乎能很好地处理服务器性能和请求成本的方差。但我们有没有更好、更简单的算法呢?答案是肯定的。

这称为“最少连接”负载均衡法。

因为负载均衡器位于服务器和用户之间,所以它可以准确地跟踪每台服务器有多少未完成的请求。然后当一个新的请求进来并且该确定将它发送到哪里时,负载均衡器已经知道哪些服务器要做的工作是最少的,并且会优先考虑这些服务器。

无论存在多少方差,该算法都表现得非常好。它能准确掌握每台服务器正在做什么的信息,从而消除了不确定性。而且它的另一个好处是实施起来非常简单。由于这些原因,你会发现这个算法是 AWS 负载均衡器的默认 HTTP 负载均衡方法。它也是 nginx 中的一个选项,如果你从未更改过它的默认设置,这个算法非常值得一试。

我们来看看这个算法在类似的复杂模拟中的实际效果。这里用的参数同上面为动态加权循环算法提供的参数是一样的。同样,这些参数在给定范围内是随机的,因此请刷新页面以查看新情况。

虽然这个算法在简单性和性能之间取得了很好的均衡,但它无法避免丢弃请求的情况。但是你会注意到,这个算法只有在实际上没有更多可用队列空间的状况下才会丢弃请求。它能确保所有可用资源都被用上,这让它成为了大多数工作负载的绝佳默认选项。

五、延迟优化

到目前为止,我一直在回避讨论的一个关键部分:我们要优化什么指标。我之前一直把放弃请求当作是很糟糕的结果,并试图避免它们。这是一个不错的目标,但它并不是我们在 HTTP 负载均衡器中最想优化的指标。

我们更关心的指标一般是延迟。这是从创建请求到处理请求的时间,以毫秒为单位。当我们讨论延迟时,通常会谈论不同的“百分位数”。例如,第 50 个百分位数(也称为“中位数”)定义为 50%的请求低于该值(单位为毫秒),50%的请求高于该值。

我用相同的参数运行了 3 次模拟,持续 60 秒,每秒都会进行各种测量。3 次模拟的差异仅来源于所使用的负载均衡算法。我们来对比 3 个模拟的中值:

image.png

你可能没想到的是,循环法的延迟中值是最好的。如果我们不看其他数据点,得出的结论就会有问题。我们来看看第 95 个和第 99 个百分位数。

image.png
注意:每种负载均衡算法的不同百分位数之间没有颜色差异。更高的百分位数在图表上总是更高的。

我们看到循环法在较高的百分位数中表现不佳。可是为什么循环法的中位数表现很好,但第 95 个和第 99 个百分位数很差呢?

在循环法中不考虑每台服务器的状态,因此会有相当多的请求转到空闲服务器,于是第 50 个百分位的延迟就很低。另一方面,算法也很乐意将请求发送到过载的服务器上,因此第 95 和 99 个百分位数很差。

我们可以看看直方图形式的完整数据:

image.png

我为这些模拟调整了参数以避免丢弃任何请求,这样 3 种算法的数据点数量就是一样的。我们再次运行模拟,这次增加 RPS 值,目的是将所有算法推到它们可以处理的范围之外。以下是丢弃请求随时间积累的图表。

image.png
最少连接算法可以更好地处理过载,但这样做的代价是 95%和 99%的延迟略高。根据你的用例情况,这可能是一个值得接纳的权衡。

六、最后一个算法

如果我们真的想针对延迟做优化,我们需要一种将延迟考虑在内的算法。如果我们可以将动态加权循环算法与最少连接算法结合起来,那不是很好吗?我们可以得到加权循环法的延迟优势和最少连接法的弹性优势。

事实证明,在我们之前就有人有了这样的想法。下面是对称为“峰值指数加权移动平均值”(或 PEWMA)的算法的模拟。这是一个又长又复杂的名字,但坚持住,我稍后会详细解释它的工作原理。

我为这个模拟设置了特定的参数,保证它表现出预期的行为。如果你仔细观察,你会注意到算法会在一段时间后停止向最左边的服务器发送请求。它这样做是因为它发现其他服务器都更快,并且不需要向最慢的服务器发送请求——这只会导致请求有更高的延迟。

那么它是如何做到的呢?它将动态加权循环与最少连接法结合了起来,并加上了一点独创的魔法。

对于每台服务器,该算法会跟踪最近 N 个请求的延迟。算法不是用这个数据来计算平均值,而是对值求和,但比例因子呈指数下降。这会产生一个值,其中延迟时间越长,它对总和的贡献就越小。最近的请求相比老的请求对计算的影响更大。

然后将该值乘以服务器的开启连接数,我们用得出来的结果值来选择将下一个请求发送到哪台服务器上。这个值越低越好。

那么它是如何做比较的呢?首先,我们来看一下第 50、95 和 99 个百分位数与之前的最少连接法数据的对比。

image.png

我们看到结果有了全方位的显著改善!新算法在较高的百分位数上优势更为明显,但中位数也一直有优势。下面我们来看直方图形式的相同数据。

image.png

请求丢弃的情况如何?

image.png

它开始表现得更好,但随着时间的推移开始差于最少连接法,这是有道理的。PEWMA 是机会主义的,因为它试图获得最佳延迟,这意味着它有时可能会让服务器负载不足。

我想在这里补充一点,PEWMA 有很多可以调整的参数。我为这篇文章编写的实现使用的配置似乎比较适合我的测试场景,但进一步调整参数可以获得比最少连接法更好的结果。这是 PEWMA 与最少连接法相比的一项劣势:额外的复杂性。

七、总结

我在这篇文章上花了很长时间。我们很难在现实主义与简单易懂之间取得平衡,但我对最终成文还是很满意的。我希望读者能够通过本文理解这些复杂系统在理想和不太理想的情况下,实践的行为方式,这样可以帮助大家直观地了解它们在什么情况下最适用于你的工作负载。

免责声明:你一定要牢记自己的负载才是永远的基准,不要把网上看来的建议视为福音。我在这里的模拟忽略了一些现实场景中的限制(服务器启动慢、网络延迟之类),而且为了展示每个算法的特定属性做了参数调整。它们并不是反映现实情况的基准测试。

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

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

相关文章

pycharm配置python3.8版本专门用于undecteded_chromedriver测试

pycharm配置python3.8版本专门用于undecteded_chromedriver测试 作者:虚坏叔叔 博客:https://pay.xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 一、Pycharm及python环境的配置 1.安装python-3.8.7rc1-amd64.e…

医学影像归档与通讯系统(PACS)系统源码 PACS三维图像后处理技术

医学影像归档与通讯系统(PACS)系统源码 PACS三维图像处理 医学影像归档与通讯系统(PACS)系统,是一套适用于从单一影像设备到放射科室、到全院级别等各种应用规模的医学影像归档与通讯系统。PACS集患者登记、图像采集、…

NUWA论文阅读

论文链接:NUWA: Visual Synthesis Pre-training for Neural visUal World creAtion 文章目录 摘要引言相关工作视觉自回归模型视觉稀疏自注意 方法3D数据表征3D Nearby Self-Attention3D编码器-解码器训练目标 实验实现细节与SOTA比较T2I微调T2V微调V2V微调Sketch-t…

基于SpringBoot的信息化在线教学平台的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 学生信息管理 教师信息管理 学生成绩管理 留言板 学生注册管理 留言反馈 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已…

数据结构 2.1 单链表

1.单链表 线性表:1.有限的序列 2.序列中的每一个元素都有唯一的前驱和后继,除了开头和结尾的两个节点。 顺序表:分配一块连续的内存去存放这些元素,eg、数组 链表:内存是不连续的,元素会各自被分配一块内…

vue3 element-ui-plus Carousel 跑马灯 的使用 及 踩坑记录

vue3 element-ui-plus Carousel 跑马灯 的踩坑记录 Carousel 跑马灯首页跑马灯demo Carousel 跑马灯 首先&#xff0c;打开其官网-跑马灯案例 跑马灯代码&#xff1a; <el-carousel :interval"5000" arrow"always"><el-carousel-item v-for"…

【高级rabbitmq】

文章目录 1. 消息丢失问题1.1 发送者消息丢失1.2 MQ消息丢失1.3 消费者消息丢失1.3.1 消费失败重试机制 总结 2. 死信交换机2.1 TTL 3. 惰性队列3.1 总结&#xff1a; 4. MQ集群 消息队列在使用过程中&#xff0c;面临着很多实际问题需要思考&#xff1a; 1. 消息丢失问题 1.1…

深度学习——实战Kaggle比赛:预测房价

深度学习——实战Kaggle比赛&#xff1a;预测房价 文章目录 前言一、Kaggle初识1.1. 注册Kaggle账号1.2. 进入房价预测比赛页面 二、预测房价实战2.1. 下载和缓存数据集2.2. 访问和读取数据2.3. 数据预处理2.4. 训练2.5. K折交叉验证2.6. 模型选择2.7. 提交Kaggle预测 总结 前言…

Unicode与UTF-8

软件开发中乱码问题经常遇到&#xff0c;Unicode&#xff0c;UTF-8, ASCII等都是高频词语&#xff0c;不过具体是啥意思其实都不清楚。这个周末研究了一下&#xff0c;略有了解&#xff0c;记录一下。 Unicode Unicode本身是纯理论的东西&#xff0c;和具体计算机实现无关。它…

【数据库——MySQL】(15)存储过程、存储函数和事务处理习题及讲解

目录 1. 题目1.1 存储过程1.2 存储函数1.3 事务处理 2. 解答2.1 存储过程2.2 存储函数2.3 事务处理 1. 题目 1.1 存储过程 创建表 RandNumber &#xff1a;字段&#xff1a;id 自增长&#xff0c; data int&#xff1b; 创建存储过程向表中插入指定个数的随机数&#xff08;1-…

Godot 官方2D游戏笔记(1):导入动画资源和添加节点

前言 Godot 官方给了我们2D游戏和3D游戏的案例&#xff0c;不过如果是独立开发者只用考虑2D游戏就可以了&#xff0c;因为2D游戏纯粹&#xff0c;我们只需要关注游戏的玩法即可。2D游戏的美术素材简单&#xff0c;交互逻辑简单&#xff0c;我们可以把更多的时间放在游戏的玩法…

局部放电发生因素与局部放电试验的重要性

局部放电发生的几个因素&#xff1a;   ①电场过于集中于某点&#xff1b;   ②固体介质有气泡&#xff0c;有害杂质未除净&#xff1b;   ③油中含水、含气、有悬浮微粒&#xff1b;   ④不同的介质组合中&#xff0c;在界面处有严重的电场畸变。   局部放电试验的重…

用VLD调查VC内存泄漏

一、发现内存泄漏 使用VS2022&#xff0c;发现提示有内存泄漏&#xff0c;检查了所有的new&#xff0c;确认都有相应的delete释放。 Detected memory leaks! Dumping objects -> {1914} normal block at 0x0000021FDFFBD2E0, 48 bytes long.Data: < >…

七、【套索工具组】

文章目录 套索工具多边形套索工具磁性套索工具 套索工具 如下图&#xff0c;以我们抠图为例&#xff0c;当我们选用套索工具选中一块区域后&#xff0c;然后按ShiftF5调出填充工具菜单&#xff0c;然后再选中内容识别&#xff0c;就可以去掉该区域&#xff1a; 那么如何做到加…

机器学习:随机森林

集成学习 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习方法&#xff0c;通过将多个基本学习算法的预测结果进行组合&#xff0c;以获得更好的预测性能。集成学习的基本思想是通过结合多个弱分类器或回归器的预测结果&#xff0c;来构建一个更强大的集成模…

【redis学习笔记】缓存

redis主要的三个应用场景 存储数据缓存消息队列&#xff08;redis本来是设计用来作为消息队列的&#xff09; redis常用作mysql的缓存 因为MySQL等数据库&#xff0c;效率比较低&#xff0c;所以承担的并发量就有限。一旦请求数量多了&#xff0c;数据库的压力就会很大&#…

字符串和内存函数

目录 strlen 模拟实现 长度不受限字符串函数 strcpy 模拟实现 ​编辑 strcat 模拟实现 strcmp 模拟实现 长度受限字符串函数 strncpy 模拟实现 strncat strncmp strstr 模拟实现 strtok strerror perror 字符分类函数 字符转换 示例&#xff1a; ​编辑内…

Android SurfaceFlinger导读(04)理解BufferQueue

该系列文章总纲链接&#xff1a;Android GUI系统之SurfaceFlinger 系列文章目录 说明&#xff1a; 关于导读&#xff1a;导读部分主要是方便初学者理解SurfaceFlinger代码中的机制&#xff0c;为后面分析代码打下一个更好的基础&#xff0c;这样就可以把更多的精力放在surfac…

不死马的利用与克制(基于条件竞争)及变种不死马

不死马即内存马&#xff0c;它会写进进程里&#xff0c;并且无限地在指定目录中生成木马文件 这里以PHP不死马为例 测试代码&#xff1a; <?phpignore_user_abort(true);set_time_limit(0);unlink(__FILE__);$file .test.php;$code <?php if(md5($_GET["pass…

项目规划得心应手:Plane 助你打造高效能团队 | 开源日报 No.48

streamlit/streamlit Stars: 27.5k License: Apache-2.0 Streamlit 是一个快速构建和共享数据应用程序的方法。它可以将数据脚本转换为可分享的 Web 应用&#xff0c;只需几分钟即可完成。该项目完全由 Python 编写&#xff0c;开源且免费&#xff01;一旦创建了一个应用程序&…