让我们从技术角度定义可伸缩性开始。维基百科对可伸缩性的定义是系统、网络或流程处理不断增长的工作量的能力,或为适应这种增长而进行扩展的潜力。问题是,软件系统的哪些关键属性允许它伸缩,以及防止伸缩的反模式是什么?或者换句话说,如何确定和评估系统架构的可伸缩性?

 

虽然详尽的列表超出了本文的范围,可以使用可伸缩性多维数据集并应用分析方法,快速确定系统将在何处遇到问题与瓶颈。可伸缩性多维数据集是一种规模设计模型,可以广泛应用于构建弹性系统架构。这是一个最佳实践模型,描述了《可伸缩性的艺术》一书中的所有可伸缩性维度。

 

可伸缩性多维数据集由x轴、y轴、z轴组成:

  1. 1.    技术架构分层(x)-没有单点故障。所有组件、服务可以水平不断扩展。

  2. 2.    功能分解分割-模块和微服务的组件化(y)。将各个应用系统、中间件、存储等按业务分割为故障隔离的不同泳道。

  3. 3.    水平数据分区——切分(z)

 

如何评估系统架构的可伸缩性?_解决方案

                                                   图1

 

在设计解决方案时,多维数据集帮助团队谨记影响系统规模和可伸缩性的关键维度。可伸缩性就是设计在不影响性能的情况下支持不断增长的客户流量的能力。重要的是要理解在设计可伸缩的解决方案时没有灵丹妙药

 

如果多层体系结构中的每个层都是可伸缩的,那么系统的整体架构就是可伸缩的。例如,一个设计良好的应用程序应该能够在流量增加或减少时无缝伸缩,并且具有足够的弹性来承受一个或多个计算节点或资源的故障。

 

可以从典型的单体结构(monolithic)应用程序开始。必须整体部署的大型系统一般来说很难扩展,在应用程序设计为无状态的情况下,可以通过添加更多的机器(虚拟的或物理的节点)来进行扩展。然而由于大型单体结构的应用功能未做拆分,因此不能单独更新小的组件,而是针对整个单体应用添加实例,因此也就需要性能强大的服务器,从这个角度来说成本效益不高。此外,广泛的回归测试也有风险。相反,如果使用容器(例如Docker)的基于微服务的体系结构,它允许独立部署小块、单个服务的应用(规模与粒度更小),而不是一个大型单体结构应用程序。

 

单体结构应用程序还有其他负面影响,比如开发复杂性。什么是开发复杂性”? Brooks的定律指出,在一个已经延期的项目中添加更多的软件开发人员会使项目变得更加遥遥无期。例如,在开发环境引入一个复杂的解决方案可能会减缓开发人员的速度,并且随着越来越多的开发人员添加各种各样的组件或功能点,情况会变得更糟。这导致系统在开发人员机器上的加载时间越来越长,特别在修改相同的文件时,代码的提交与合并也会是一个大麻烦。

 

开发复杂性问题的另一个例子是架构或数据库的大量过时部分,其中一个人是专家,那么该人员会成为系统特定部分更改的瓶颈。而且,如果它们是唯一理解这个单体结构应用的人,那么它们实质上就是单点故障。整体的复杂性和代码更改的速度使得任何开发人员都很难了解系统的所有特性,因此也就引入了更多的缺陷。而拆分为微服务或更小粒度组件的解耦系统有助于预防这个问题。

 

在验证数据库设计是否具备可伸缩性时,需要检查一些关键的反模式。例如:

在检索或写入数据时,同步数据库访问是否会阻塞到数据库的其他连接?这种设计可能会阻塞查询并阻塞应用程序。

查询SQL的编写是否高效?大量的数据占用(大范围的锁定)会迅速降低数据库性能。

应用程序中是否存在依赖于单个事务数据库的重报表函数?生成报告会严重影响关键用户场景的性能。从读写数据中分离只读数据可以积极地提高可伸缩性。

数据可以跨不同的负载数据库和/或数据库服务器(分片)进行分区吗?例如,不同地理位置的客户可能被划分到与他们的位置更兼容的各种服务器。分离数据允许增强伸缩性,因为可以分离请求。

是否使用了合适的数据库技术?blob存储在关系数据库中会产生负面影响——相反,应该使用更合适的技术,例如NoSQL文档存储。将结构化程度较低的数据放到关系数据库中(比如MySQL)也会导致浪费和性能问题,在这里,NoSQL解决方案可能更合适。

 

很多遗留的代码中流行的软件反模式,通常会将UI代码与底层逻辑混杂在一起。这种做法使得扩展应用程序的各个层次变得异常艰难,并且很难进行A/B测试以验证不同UI。分层原则允许在每个层上放置足够的硬件,以实现更少的资源使用和总体成本效率。业务逻辑与SPROCs(存储过程)的分离也会提高系统的可维护性和可伸缩性。

 

另一个关键领域是有状态应用服务器。将状态存储在单个服务器上的应用程序对于可伸缩性来说是致命的。例如,如果某个业务逻辑在一台服务器上运行,并且只在一台服务器上的缓存中存储用户会话信息(或其他数据),那么所有用户请求都必须使用同一个服务器节点,而不是集群中的任何一个节点。这就没办法添加新的节点来增强负载均衡以降低节点负载。缓存对于性能来说是一个很好的实践,但要小心规划、设计并使用,尤其不能干扰系统的水平伸缩能力。

 

最后,长时间运行的作业和/或同步依赖也是可伸缩性问题的关键领域。在系统上触发处理时间为分钟或更多的操作会影响可伸缩性(例如,需要生成大量数据的报表的执行)。阻塞操作会使系统的可用性降低。一般来说,建议将长时间运行的请求排队并在后台执行它们(针对报表类可以选择T+1),在事件完成时发送消息(异步通信),避免或减少占用关键应用程序和数据库服务器的资源。针对耗时较长的请求,同步调用与依赖系统进行通信也会影响性能、可伸缩性和可靠性。可以通过异步消息传递来解耦,常见解决方案包括RabbitMQ(注:RocketMQ可能是更好的选择)和Kafka

 

以上的列表并不详尽,但是概述了评估系统整体架构的可伸缩性时所关联的一些关键领域。

 

原文作者:Robin McGlothin  译者:江玮

版权声明:本文版权归作者(译者)及号所有,欢迎转载,但未经作者(译者)同意必须保留此段声明,且在文章页面明显位置给出,本文链接如有问题,可留言咨询。