nginx swrr负载均衡算法的二宗罪及其改进的思考

目录

  • 1. swrr负载均衡算法的二宗罪
    • 1.1 第一宗罪: 共振引起系统崩溃
    • 1.2 第二宗罪: 吃CPU大户
  • 2. 对swrr负载均衡算法的改进的思考
    • 2.1 “共振”问题的解决
    • 2.2 “吃CPU大户”问题的解决

1. swrr负载均衡算法的二宗罪

   swrr是一种基于加权轮询的负载均衡算法。它根据服务器的权重来分配请求。具体而言,swrr维护一个服务器列表,每个服务器都有一个权重值,表示其处理请求的能力。当一个请求到达时,swrr会按照服务器的权重顺序依次将请求转发到服务器上,然后更新服务器的权重。这样可以实现将请求均匀地分配给具有不同处理能力的服务器。关于swrr的实现原理可以参考我的博文《深入理解nginx负载均衡round-robin算法》。

   nginx的官方原生的round-robin功能就是基于swrr算法来实现的。就如其名字swrr表明的,Smooth Weighted round-robin,它比最简单的round-robin功能有了重要的改进,它不是简单的依次轮询,而是按照服务器权重平滑分配的能力,一定程度上避免了rs服务器的突发峰值的问题。

  本文要细数一下swrr的两宗罪:

1.1 第一宗罪: 共振引起系统崩溃

  我们先来看看阿里的真实案例。《阿里七层流量入口负载均衡算法演变之路》中提到的一个压测案例,当一个机房内的接入层tengine统一将某个rs服务器的权重从1改成2以后,被调高权重rs服务器的流量瞬间冲高了50倍左右,并且持续了7s左右的时间后QPS开始下降,流量才逐渐恢复到预期的值。

  该文中给出了相关现象的详细描述,但是具体什么原因却没有详细说明。这里就来分析一下。对于swrr,如果按照nginx单个进程来说,其实它已经做得足够好了,顾名思义,它已经是平滑的了。但是,如果我们放在一个拥有32核心,甚至64核心或者更多的服务器上,那么我们开启的nginx worker进程就是32,或者64个,如果再像阿里的压测环境,可能又有几十台作为负载均衡功能的nginx前端接入服务器,那么可能就是并发运行的nginx进程就有几百个甚至上千个。swrr在每个进程中都会被初始化为一个状态,如果有三个rs server分别为A、B、C,并假设通过swrr算法,但个进程依次分配rs得到以下序列 B、C、A、B、A、C…

  另外,假设总共有100个nginx worker进程在运行,我们可以想象到,第一个请求进来的时候,因为所有的nginx进程分配的第一个rs必然是B,因此第一个请求分配到的rs是B的概率是100%,那么第二个请求进来的时候,因为有99个进程将分配B,而之前分配了B的服务器将分配C,那么分配到B的概率将是99%,依次类推,第三个请求分配到B的概率也97%,这就导致了B服务器的压力在短时间内会飚得特别高,就像《阿里七层流量入口负载均衡算法演变之路》中给出的那个图像一样:

在这里插入图片描述

  所以,关键的问题在于每个nginx的worker进程因为每个进程都步调一致,导致了“共振现象”,引起了部分rs服务器的流量突发性增高,和原本的预期背道而驰了。我们回顾一下中学物理上面介绍的一个经典的军队用统一步伐过桥最终引起大桥垮塌的案例就可以与这个案例引起共鸣,一言以蔽之,swrr引起的流量突发也是因为“共振”引起的流量突发。

  当然,随着时间的推移,最终每个进程由于分配到的请求的随机性因素,由于swrr的平滑负载均衡能力,必然会慢慢达到预期的负载效果,但是,我们要注意的是,前提是因为流量突发,这些rs服务器都能够扛过流量洪峰的袭击才可以,而往往可能因为流量洪峰过来的时候,部分rs服务器服务器早就挂掉了,导致引起整个系统的雪崩,根本来不及达到最终的预期的负载均衡效果。

1.2 第二宗罪: 吃CPU大户

  swrr算法在我们平常的小规模的负载均衡系统中,譬如rs服务器只有几台,最多10几台的情况下,其实是可以运行得很好的,所以我们一般也不会碰到这种问题。但是,放在一个大规模的集群环境中,就像《 QPS 比 Nginx 提升 60%,阿里 Tengine 负载均衡算法揭秘》提到的那样,如果upstream中设置的rs服务器有2000台,swrr的“吃CPU大户”的弊端就会暴露无遗了。我们先来看看swrr算法的代码,以下是我参照nginx的round-robin代码写的一段c代码:

// effective_weight 三台rs服务器,设置了每台rs服务器对应的权重
int ew[] = {1,2,4};           

#define PN   sizeof(ew)/sizeof(int)

// current_weight 对应三台rs服务器的计算出来的本轮权重 
int cw[PN] = {0};

int rr()
{
	int i;

	int ttl = 0;

	int cur_w = -1;
	int cur = -1;

	for (i=0; i < PN; i++) {
		cw[i] += ew[i];
		ttl += ew[i];

		if (cur_w < cw[i]) {
			cur = i;
			cur_w = cw[i];
		}
	}

	cw[cur] -= ttl;
	
	return cur;
}

   具体算法的逻辑就不再这里介绍了,可以参考《 QPS 比 Nginx 提升 60%,阿里 Tengine 负载均衡算法揭秘》。需要注意的一点是,swrr算法每次进行负载均衡选择一台rs服务器,都需要进行一次完整的遍历,有2000台rs那么就需要循环2000次,这就是问题的所在。就像上面说的那样,对于upstream中rs数量少的情况大家可能感受不到,如果有2000台rs的规模,那大量的cpu资源就白白浪费在循环上了,确实和nginx是从头到尾塑造的“高效率”web服务器的形象大相径庭。

2. 对swrr负载均衡算法的改进的思考

2.1 “共振”问题的解决

  在中学物理军队用统一步伐过桥最终引起大桥垮塌的案例中,物理老师告诉我们的解决办法是改齐步走为便步走,便步走就引入了随机性,这样就很好地避免了共振的发生。而我们swrr算法也同样可以通过引入随机性来解决“共振”现象的发生。所以阿里的tengine中引入了vnswrr算法,该算法就是引入了“随机性”,虽然每个nginx进程还是使用swrr算法,但是每个nginx进程引入了一个随机值,在其第一次初始化完首批所谓的“虚拟节点”列表后,每个进程会设置一个随即的起始轮询位置,这样每个进程各自走各自的“便步”,从而避免了“共振”的发生。

 emsp;当然,我们如果不考虑解决CPU消耗的问题,我们完全可以不用虚拟节点的办法,在nginx初始化负载均衡算法加载完成peer列表以后,每个进程随机地取一个[0,N)中的值n, N为peer数量,预先执行n遍swrr算法,从而强行使得各个进程的步调不一致,一样可以解决这个问题。

  当然,如果我们只有少数几台nginx服务器作为负载均衡服务器,那么我们完全不用那么负载,利用nginx官方原生的ngx_http_upstream_zone_module模块也就能很好地解决问题了。关于ngx_http_upstream_zone_module模块的详细说明可以参考《深入理解nginx upstream共享内存机制》。因为ngx_http_upstream_zone_module将peer的分配状态放在共享内存中,每个worker进行负载均衡的时候,会线性地执行swrr算法,swrr算法的当前状态也会更新的共享内存中,还是拿军队过大桥的例子来说,ngx_http_upstream_zone_module模块会限制每个人一个一个过桥,而不是大家一起过桥,从而避免了"共振"问题的发生。

2.2 “吃CPU大户”问题的解决

  解决这个问题最理想的方法就是在负载均衡的时候把循环去掉,把算法的复杂度从O(n)改称O(1)。如果理解了swrr算法,要改起来也不是太复杂,因为swrr算法每Total Weight(即所有服务器分配的权重的总和)次负载均衡请求,就会回到原始状态并重新开始。因此,我们可以提前把分配表建好,后续进行负载均衡的时候,只要对着这个分配表每次往后移动一格就可以了,自然就实现了O(1)的性能。

  不过,tengine的vnswrr算法考虑得更加全面一些,因为如果rs服务器数量非常多的情况下,一次性生成这个分配表的计算量也是不少的,计算量是O(n*w)(w为总的权重)的,如果是两前台服务器,计算量也是相当可观的,所以vnswrr就将这个分配表的生成任务化整为零,每次只生成固定的几个,用完再分配,直到整个分配表填充完毕后就循环利用分配表进行执行负载均衡分配rs服务器就可以了,这样就大大降低了CPU使用率的突发问题,提升了系统的抗压能力。

  从阿里压测给到的数据来看,用wrk 压测工具、500 并发、长连接场景、upstream 配置 2000 个 server的测试条件下。Nginx 官方的 SWRR 和改进的 VNSWRR 算法下的 QPS 处理能力如下图所示:其中 VNSWRR 的 QPS 处理能力相对于 SWRR 算法提升 60% 左右。

  至于vnswrr的详细算法原理,可以参考《阿里七层流量入口负载均衡算法演变之路》](https://www.upyun.com/opentalk/444.html),后续本人也将单独写一篇关于ngx_http_upstream_vnswrr_module模块源码分析的文章,敬请期待。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一款 Windows C盘文件清理工具

推荐一款 Windows C盘清理工具 0. 引言1. 下载地址 0. 引言 Windows 在使用过程&#xff0c;C盘的空间会变得越来越少。 Windows在C盘放了很多缓存&#xff0c;临时文件&#xff0c;我们自己还不敢乱删。 今天试了1款工具&#xff0c;可以很方便的查看C盘各个文件夹的文件大小…

中间件 | RabbitMq - [AMQP 模型]

INDEX 1 全局示意2 依赖 1 全局示意 AMQP&#xff0c;即高级消息队列协议&#xff08;Advanced Message Queuing Protocol&#xff09;&#xff0c;整体架构如下图 producer 发送消息给 rabbit mq brokerrabbit mq broker 分发消息给 consumer消费producer/consumer 都通过 …

【Echarts】曲线图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

蝙蝠避障:我生活中的一道光

盲人的世界&#xff0c;是无尽的黑暗。看不见光&#xff0c;看不见色彩&#xff0c;甚至看不见自己的手。但在这个黑暗的世界里&#xff0c;我找到了一个光明的出口&#xff1a;一款可以障碍物实时检测的名为蝙蝠避障的盲人软件。 这款软件就像是我的一双眼睛。它通过先进的激光…

探索HDFS读写流程、节点机制和数据完整性

目录 写在前面一、HDFS的读写流程1.1 HDFS写数据流程1.2 机架感知1.3 HDFS读数据流程1.4 小结 二、 NameNode和SecondaryNameNode2.1 NN和2NN工作机制2.2 Fsimage和Edits解析2.2.1 oiv查看Fsimage文件2.2.2 oev查看Edits文件 2.3 CheckPoint时间设置 三、DataNode3.1 DataNode工…

Spring Cloud Alibaba微服务从入门到进阶(二)

Spring Boot配置管理 1、application.properties 2、application.yml 1.内容格式比较&#xff1a; .properties文件&#xff0c;通过 . 来连接&#xff0c;通过 来赋值&#xff0c;结构上&#xff0c;没有分层的感觉&#xff0c;但比较直接。 .yml文件&#xff0c;通过 &…

攻防演练|某车企攻防小记

前言 专注于web漏洞挖掘、内网渗透、免杀和代码审计&#xff0c;感谢各位师傅的关注&#xff01;网安之路漫长&#xff0c;与君共勉&#xff01; 实习期间针对某车企开展的一次攻防演练&#xff0c;过程很曲折&#xff0c;当时的记录没有了只是简单的总结一下。 攻击路径 收…

Promise图解,Pass

10-优化代码_哔哩哔哩_bilibili

Linux运维:深入了解 Linux 目录结构

Linux运维&#xff1a;深入了解 Linux 目录结构 一、 Linux 目录结构与 Windows之间的主要区别二、Linux根目录结构三、常见目录及其作用 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、 Linux 目录结构与 Windows之间的主要区别 1、根…

中探:事件循环相关内容(因为不仅仅是初步认识,但也不至于是深入探讨,所以命名为“中探”)

下面内容写于 2022 年&#xff0c;文本描述过多&#xff0c;可能不适合有经验的人看。新的文章在 个人网站 中。 对了&#xff0c;说到事件循环&#xff0c;怎么可以离开这个最知名的视频呢&#xff01;视频是英文的&#xff0c;但即使你听不懂&#xff0c;单纯看他的操作&…

数学建模-模糊性综合评价模型

中医药是中国传统文化的重要组成部分&#xff0c;凝聚了中华民族千百年来智慧的结晶。作为中医的发源地&#xff0c;中国政府一直致力于保护、发展和推广中医药&#xff0c;采取了一系列政策措施[]。目前&#xff0c;中国面临着老龄化日益加剧&#xff0c;老年人群中慢性疾病和…

keilC51明明已经定义的变量却报错未定义与期待asm

文章目录 keil_C51采用的是C89标准&#xff1a;C89变量定义标准&#xff1a;程序块&#xff1a; expected __asm&#xff1a;已经定义某个变量却报错未定义该变量&#xff1a;从汇编语言中看&#xff1a; keil_C51采用的是C89标准&#xff1a; C89变量定义标准&#xff1a; 1…

固态存储是未来|浅析SSD架构的演进与创新技术-1

常见的SSD架构中&#xff0c;包括了SSD控制器、NAND颗粒、DRAM颗粒三大组件&#xff0c;SSD控制器的固件需要兼顾坏块管理、ECC纠错、垃圾回收GC、磨损均衡WL、NAND die介质管理、缓存交互等等。 随着时代的发展&#xff0c;SSD架构&#xff0c;也不断有新的挑战和需求。基于小…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的交通标志识别系统详解(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;本篇博客详细介绍了利用深度学习构建交通标志识别系统的过程&#xff0c;并提供了完整的实现代码。该系统采用了先进的YOLOv8算法&#xff0c;并与YOLOv7、YOLOv6、YOLOv5等早期版本进行了性能评估对比&#xff0c;分析了性能指标如mAP、F1 Score等。文章深入探…

stm32f103c8t6学习笔记(学习B站up江科大自化协)-USART串口-硬件部分

通信协议简介 USART串口 硬件电路 通信距离&#xff1a; TTL和RS232通信距离只有几十米 RS485电平通信距离可达上千米 应用场景&#xff1a; TTL用于单片机这种低压小型设备 RS232一般在大型机器上使用&#xff0c;由于环境比较恶劣静电干扰比较大&#xff0c;所以电压电平比…

javaEE13(网站第8章两个课后题)

1、对“jspservletjavabean实现分页查询”功能做如下补充&#xff1a; &#xff08;1&#xff09;记录批量删除&#xff1a;每个记录前添加复选框&#xff0c;点击批量删除&#xff0c;删除选中记录。 增加跳转到任意页功能。用户可改变每页记录条数。 页面&am…

wait 和 notify方法

目录 1.1 wait()方法 wait 做的事情: wait 结束等待的条件: 1.2 notify()方法 1.3notifyAll方法 1.4wait()和sleep()对比 由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序. 完成这个协调…

Python 的练手项目有哪些值得推荐?

Python 是一种强大的编程语言&#xff0c;有许多值得推荐的练手项目。以下是一些例子&#xff1a; 数据分析&#xff1a;利用 Python 的数据分析库&#xff08;如 pandas 和 NumPy&#xff09;处理和分析数据。你可以尝试对数据进行清洗、可视化&#xff0c;或者构建简单的预测…

4-LINUX--文件操作命令

一、文件查看命令 1. cat 1.1 查看文件内容&#xff0c;示例如下&#xff1a; 1.2 合并文件&#xff0c;示例如下&#xff1a; 1.3 往文件中写入数据&#xff0c; Ctrld 是结束输入&#xff0c;示例如下&#xff1a; 2. more 当一个文件的内容超过一个屏幕能显示的行数…

PCL点云处理之最小二乘球面点云拟合(直接拟合法,完整实验)(二百三十一)

PCL点云处理之最小二乘球面点云拟合(直接拟合法,完整实验)(二百三十一) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 现在假设有这样一群点云,它们分布在一个球的表面,可能并不严格,带有些许噪声,此时我们需要计算球心坐标和球的半径。(这里提供完整的实验过…