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

news2024/11/18 17:26:10

发展到一定阶段后,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.coloradmin.cn/o/1065072.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++设计模式-抽象工厂(Abstract Factory)

目录 C设计模式-抽象工厂(Abstract Factory) 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-抽象工厂(Abstract Factory) 一、意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们…

unity脚本_生命周期函数 c#

帧:fps 即每秒钟跑的游戏帧数 游戏的本质 是一个死循环 每一次循环处理游戏逻辑就会更新一次画面 之所以能看到画面在动 是因为切换画面的速度达到一定时人眼就认为画面时流畅的 一帧就是执行一次循环 人眼舒适放松时可视帧数 24帧/s 游戏卡顿的原因: …

C 语言的标识符,保留标识符,关键字

C99 和 C11 允许使用更长的标识符(identifier),但是编译器只能识别前 63 个字符,对于外部标识符,只允许使用 31 个字符。 实际上,可以使用更长的字符,但是编译器会忽略超出部分的字符。 如果两…

Stack和quque

102. 二叉树的层序遍历 - 力扣(LeetCode) 如图:层序遍历即一层一层遍历,从左到右。 先遍历第一层,把第一层的节点放到队列里面,levesizeq.size(),即代表队列里面有多少个值。 然后现在把队里里…

笔试编程ACM模式JS(V8)、JS(Node)框架、输入输出初始化处理、常用方法、技巧

目录 考试注意事项 先审完题意,再动手 在本地编辑器(有提示) 简单题515min 通过率0%,有额外log 常见输入处理 str-> num arr:line.split( ).map(val>Number(val)) 初始化数组 new Array(length).fill(v…

windows terminal终端美化

1,安装Windows terminal 可以选择window商店安装或者GitHub安装,安装步骤省略。 2.oh my posh 安装 安装步骤可以选择window 商店或者GitHub安装,步骤省略 3.安装字体 nerd font[官网链接] 4.配置 oh my posh ####第一次要输入以下命…

视频号规则改动,不再支持拍单,传统无货源模式已行不通!

视频号小店批量铺货行不通了,大家好我是派大星,这两天视频号发布了一个公告, 核心信息呢就是10月7号,视频号小店,将无法直接查看消费者的详细下单信息,只能通过电子面单的形式,打单发货。每个店…

RDP协议流程详解(二)Basic Settings Exchange 阶段

RDP连接建立过程,在Connection Initiation后,RDP客户端和服务端将进行双方基础配置信息交换,也就是basic settings exchange阶段。在此阶段,将包含两条消息Client MCS Connect Initial PDU和Server MCS Connect Response PDU&…

vulnhub靶机doubletrouble

下载地址:doubletrouble: 1 ~ VulnHub 主机发现 arp-scan -l 端口扫描 nmap --min-rate 1000 -p- 192.168.21.151 端口服务扫描 nmap -sV -sT -O -p22,80 192.168.21.151 漏洞扫描 nmap --scriptvuln -p22,80 192.168.21.151 先去看看web页面 这里使用的是qdpm …

【JavaEE重点知识归纳】第5节:方法

目录 一:方法的概念和使用 1.什么是方法 2.方法的定义 3.方法的调用过程 4.实参和形参的关系(重点) 二:方法重载 1.方法重载概念 2.方法签名 三:递归 1.递归的概念 2.递归执行的过程分析 一:方法的概念和使…

HttpStatusCodeException.getResponseBodyAsString 乱码

场景: 项目a进行了spring boot版本升级, 使用了2.7.15 项目b是做接口转发 (没升级spring boot版本, 用的是2.1.5) 调用过程: 请求方>>项目b>>项目a 现象: postman直接调用a中的接口, 接口报错, msg里的错误信息是正常显示 当调用接口报错时, msg里的错误信息是…

算法笔记:0-1背包问题

n个商品组成集合O,每个商品有两个属性vi(体积)和pi(价格),背包容量为C。 求解一个商品子集S,令 优化目标 1. 枚举所有商品组合 共2^n - 1种情况 2. 递归求解 KnapsackSR(h, i, c)&#xff…

Vue中如何进行数据可视化雷达图展示

在Vue中进行数据可视化雷达图展示 数据可视化是将数据以图形方式呈现的过程,雷达图是其中一种常用的图表类型,用于可视化多个维度的数据。Vue.js作为一个流行的JavaScript框架,提供了许多工具和库来实现数据可视化。本文将介绍如何使用Vue来…

git与github的交互(文件与文件夹的上传)

git与github的交互(文件与文件夹的上传) 准备:gitHub账号(创建一个新项目)与Git软件的安装 一:开启公钥SSH登录(之前配置过就跳过) 1.安装SSH 在本地新创建文件夹负责装载项目&a…

Java虚拟机内存模型

JVM虚拟机将内存数据分为: 程序计数器、虚拟机栈、本地方法栈、Java堆、方法区等部分。 程序计数器用于存放下一条运行的指令; 虚拟机栈和本地方法栈用于存放函数调用堆栈信息; Java堆用于存放Java程序运行时所需的对象等数据&#xff1b…

桌面应用开发:Go 语言和 Web 技术的融合创新 | 开源日报 No.46

TheAlgorithms/Python Stars: 161.5k License: MIT 这个开源项目是一个用 Python 实现的算法库,旨在提供教育目的下使用的各种算法。 提供了大量常见算法的 Python 实现。适合学习和教育目的,可以帮助读者更好地理解不同类型的算法。 airbnb/javascri…

AI:08-基于深度学习的车辆识别

随着汽车行业的迅速发展,车型识别在交通管理、智能驾驶和车辆安全等方面变得越来越重要。基于深度学习的车型识别技术为实现高效准确的车辆分类和检测提供了强大的工具。本文将介绍如何利用深度学习技术来实现车型识别,并提供相应的代码示例。 数据收集和预处理: 为了训练…

PHP 行事准则:PHP 配置文件

文章目录 参考环境PHP 行事准则PHP 配置文件php.ini-production 与 php.ini-development生产配置文件开发配置文件配置文件的应用版本差异 修改配置的生效 PHP 运行时配置ini_set()布尔配置项限制 phpinfo()phpinfo 页面Core 参考 项目描述搜索引擎Bing、GoogleAI 大模型文心一…

软件设计师学习笔记11-磁盘管理+IO管理软件+文件管理+作业管理

目录 1.磁盘管理 1.1磁盘(了解一下) 1.2读取磁盘数据的时间 1.3 磁盘调度算法 1.3.1常见的磁盘调度 1.3.2 先来先服务(FCFS) 1.3.3 最短寻道时间优先(SSTF) 1.4 例题补充(均来自希赛软考) 1.4.1 单/双缓冲区花销时间的计算 1.4.2 SSTF 1.4.3 磁道物理块花销时间计算…

UE5.1编辑器拓展【三、脚本化资产行为,删除无引用资产】

目录 需要考虑的问题 重定向的修复函数 代码: 删除无引用资产 代码 需要添加的头文件和模块 在我们删除资产的时候,会发现,有些资产在删除的时候会出现有被什么什么引用,还有的是没有被引用。 而我们如果直接选择一片去进行…