我们一起聊聊软件架构伸缩性法则

2024年 4月 3日 60.0k 0

对于大部分商业和政府部门的系统,初始的开发和部署更侧重于实现功能的可用性和创新性,而不是可伸缩性。在早期阶段,只要系统能够应对现有的工作负载,开发团队就会优先考虑引入新功能以提升业务价值。然而,随着系统的发展,性能和可伸缩性逐渐成为关键问题,甚至关乎系统的生存。在这一点上,架构师需负起责任,将系统改造为能够快速响应并支持伸缩性的架构。

成本和伸缩性之间的关系

对系统进行伸缩的一个核心原则是能够方便地添加新资源来处理增长的负载。对于很多系统来说,一个简单而有效的方法是部署多个无状态服务器实例,并使用负载均衡器在这些实例之间分配请求,如下图。

图片图片

在云平台部署资源时,成本主要由两部分构成:

一是每个虚拟机服务器实例的部署成本

二是负载均衡器的成本,后者取决于新的和活跃的请求数量以及处理的数据量。随着请求量的增加,已部署的虚拟机需要具备更高的处理能力,导致成本上升。

同时,负载均衡器的费用也会随着请求和处理的数据量的增加而增长。因此,成本的增加与系统规模的扩大是相互影响的,可伸缩性设计的选择将不可避免地影响到部署成本。忽略这个因素可能导致意外的高昂费用。

为了控制成本,主要有两个策略:采用弹性负载均衡器自动根据实际请求量调整服务器实例的规模;以及提升每个服务器实例的处理能力,通常通过优化服务器配置(如线程数量、连接数量、堆内存大小等)实现。通过精心调整这些参数,可以显著提升性能和处理能力,进而降低成本。

注意系统瓶颈

对一个系统进行伸缩本质上就是要增加它的容量。在上面的示例中,我们通过部署更多的服务器实例来提高请求处理能力。

但是,软件系统是由多个相互依赖的处理元素或微服务组成的,所以在增加一部分微服务容量的同时,不可避免地会被其他一些微服务拖累。在我们的负载均衡示例中,假设服务器实例都连接到同一个共享数据库。随着部署服务器数量的增加,数据库的请求负载也随之增加 (如下图)。

图片图片

达到一定阶段时,数据库性能会成为限制因素,导致访问速度明显下降。

这时,即便增加服务器的处理能力,也无法从根本上解决问题,因为问题出在数据库上。要想实现进一步的系统扩展,就必须增强数据库的处理能力。这可以通过优化查询语句、增配CPU或内存资源、执行数据库复制或分片等多种方式来实现。

当然,还有许多其他方法可以缓解这个问题。系统内的任何共享资源都可能变成性能瓶颈。在增加系统的某个部分的能力时,必须考虑到对下游部分的影响,避免因增强而引起系统的其他部分突然承受不住压力,这种情况可能会导致连锁反应,进而使整个系统崩溃。数据库、消息队列、网络连接的长时间延迟、线程及连接池和共享的微服务等,都是潜在的性能瓶颈所在。一旦面临高流量负载,这些瓶颈点很快就会暴露出来。因此,关键在于一旦瓶颈出现,能够防止系统突然崩溃,并能迅速扩展系统能力以应对。

慢服务比故障服务更有害

在正常情况下,系统应该能够为微服务和数据库提供稳定、低延迟的通信。当系统负载保持在正常的配置水平时,性能是可预测、一致和快速的,如下图所示。

图片图片

当客户端的请求量超出常规范围时,微服务架构中服务间的请求响应时间会开始延长。这尤其明显当进入的请求负荷超过了某个特定服务(例如服务B)的处理能力时,这时未处理完的请求就会在前置微服务(例如服务A)中累积。因为下游服务的处理速度减缓,导致这个微服务接收到的请求量超过了它能够完成的请求量。

图片图片

当服务因为波动或资源耗竭面临压力过大而无法正常响应客户端请求时,客户端会经历延迟,这种情况可能引起连锁反应,即级联故障——一个响应缓慢的服务导致沿请求链路的请求积压,进而可能造成整个系统的崩溃。

为了防止这种级联故障,可以采用一些架构模式,例如回路断路器和隔板。回路断路器在检测到服务延迟超过预设阈值时,可以自动减少请求流向该服务,或完全切断对其的请求,以防止系统过载。隔板则通过隔离下游服务的故障,保护上游服务不受影响,从而在一个服务出现问题时,避免整个系统受损。这些策略有助于构建出更加弹性和可扩展的系统架构。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论