1.1 可扩展性的定义
直观地说,可扩展性是一个非常简单的概念。维基百科对它的定义(https://oreil.ly/JsYXf)是“可扩展性是通过添加更多资源来处理越来越多的工作的系统属性”。我们都知道如何扩展一个高速公路系统——增加更多的车道,这样它就可以承载更多的车辆。我喜欢的一些人知道如何扩大啤酒生产规模——他们通过增加酿造容器的数量和扩大容器的体积、增加执行和管理酿造啤酒的人员数量,以及增加用来盛新鲜美味啤酒的桶的数量来实现产能扩大。任何物理系统——交通系统、机场,以及建筑物中的电梯——以及增加容量的途径都是显而易见的。
与物理系统不同,软件系统在某种程度上是无定形的。它们并非是通过外部观察就能了解其内部行为的东西,你无法指向它、看到它、触摸它和感觉它。一个软件系统就是一个数字工件(artifact)。从本质上讲,构成可执行代码和数据的1和0二进制流对于任何人来说都难以区分。那么,就软件系统而言,可扩展性意味着什么?
避免陷入定义之战,长话短说,可扩展性定义了软件系统在某个运营维度上处理增长的业务量的能力。不同运营维度的例子有:
●系统可以同时处理的来自用户或外部设备(例如传感器)的请求的数量。
●系统可以有效处理和管理的数据量。
●对系统存储的数据进行预测分析而获得的价值。
●随着请求量的增长,系统保持稳定、一致的响应时间的能力。
例如,假设一家大型连锁超市正在迅速开设新店并增加每家商店的自助结账终端的数量。这需要超市核心软件系统能够执行以下功能:
●在不缩短响应时间的情况下,处理增加的来自项目扫描的请求量。即时响应项目扫描对于维持客户满意度是必要的。
●处理和存储因销售额增加而产生的更多数据量。这些数据被用于库存管理、会计、计划和许多其他超市职能。
●从每个商店、不同地区和不同国家获取“实时”(例如每小时)销售数据摘要,并与历史趋势数据进行比较。这些趋势数据让某些地区的异常事件(意外的天气条件、活动中的大量人群等)一目了然,并帮助受影响的商店迅速做出反应。
●随着商店和客户数量的增长,改进库存订购预测子系统,以便能够正确预测销售量(以及因此需要重新订购库存商品的需求量)。
上述不同维度的要求实际上是系统可扩展性的需求。如果在一年多的时间里,这家连锁超市开了100家新店,销售额增长了400倍(有些新店很大!),那么要保证超市能够高效运营,便需要扩展软件系统以提供足够的处理能力。如果系统无法扩展并影响到客户的购物体验,那么当客户不满意时,我们会损失销售额。我们可能会因为库存滞留而增加成本。我们也可能会错失根据当地情况举办促销活动来增加销售额的机会。上述所有现象都是降低客户满意度和利润的因素,没有一个对企业有利。
因此,成功扩展系统对于我们虚构的超市的业务增长至关重要,实际上,它也关系到许多现代互联网应用程序的生存问题。但对于大多数商业和政府系统而言,在开发和部署的早期阶段,可扩展性并不是主要的质量要求。相反,增强可用性和实用性的新功能成为我们开发周期的驱动力。只要在正常负载下系统性能满足要求,我们就会不断添加面向用户的功能来提高系统的业务价值。事实上,在有明确的需求之前引入一些复杂的分布式技术(我将在本书中介绍的技术)可能对项目有害,额外的复杂性会导致开发过于保守。
尽管如此,在系统的发展过程中,提高系统性能和可扩展性成为当务之急甚至影响系统存亡的现象比比皆是。有吸引力的功能和实用性高的特性带来了成功,但也带来了更多需要处理的请求和更多需要管理的数据。这往往存在一个临界点,在轻负载下有意义的设计和决策突然变成了技术债务[1]。以下来自系统外部的事件通常会引爆临界点:2020年3月或4月的媒体上有许多关于政府失业和冠状病毒大流行导致超市在线订购网站无法承受激增的需求而崩溃的报道。
通过增加资源来增加系统在某个维度上的容量称为纵向扩展(scaling up)或横向扩展(scaling out)——稍后我将探讨它们之间的区别。此外,与物理系统不同,能够按比例缩小(scale down)系统容量以降低成本同样重要。
一个非常典型的例子是Netflix,它需要处理来自不同区域的可预测的昼夜请求。概括地说,在任何地理区域,晚上9点观看Netflix的人比早上5点要多。这使得Netflix可以在访问量较低时减少资源,从而节省了在亚马逊云中运行节点的成本,同时也带来了社会价值,如降低数据中心能源功耗等。比较一下Netflix和高速公路:高速公路晚上很少有车,但我们不会撤回车道(修理除外)。为数不多的司机可以在全部道路上随心所欲地行驶。在软件系统中,我们可以在几秒钟内扩展和收缩系统的处理能力,以满足瞬时访问量。与物理系统相比,我们部署的策略大有不同。
关于软件系统的可扩展性还有很多需要考虑的地方,让我们先探讨2021年左右的一些当代软件系统的规模,然后再回到这些问题。