第一章 可扩展性入门
本入门指南解释了可扩展性,重点阐述了垂直扩展和水平扩展之间的关键区别。
扩展是指为应用程序分配资源并高效管理这些资源,以最大限度地减少资源争用。当应用程序需要的资源超过可用资源时,用户体验 (UX) 会受到负面影响。扩展的两种主要方法是垂直扩展和水平扩展。垂直扩展方法更简单,但局限性也更大。水平扩展更复杂,但可以提供远超垂直扩展的扩展能力。水平扩展是更符合云原生理念的方法。
本章假设我们正在扩展一个分布式多层 Web 应用程序,但其中的原则也具有更广泛的适用性。
可扩展性定义
应用程序的可扩展性衡量的是它能够同时有效支持的用户数量。应用程序无法有效处理更多用户的临界点就是其可扩展性的极限。当关键硬件资源耗尽时,可扩展性就会达到极限,但有时可以通过提供额外的硬件资源来扩展可扩展性。应用程序所需的硬件资源通常包括 CPU、内存、磁盘(容量和吞吐量)以及网络带宽。
应用程序运行在多个节点上,每个节点都拥有硬件资源。应用程序逻辑运行在计算节点上,数据存储在数据节点上。还有其他类型的节点,但这些是主要的。节点可以是物理服务器、虚拟机或服务器集群的一部分,但当底层资源无关紧要时,通用术语节点就很有用。通常情况下,底层资源并不重要。
只要应用程序能够有效利用这些资源,就可以通过提供额外的硬件资源来扩展应用程序的规模。我们添加这些资源的方式决定了我们采用哪种扩展方式。
- 纵向扩展 是指通过增加现有节点内的资源来提高应用程序的整体容量。
- 横向扩展 是指通过添加节点来提高应用程序的整体容量。
这些扩展方式并非互斥,也不是非此即彼。任何应用程序都可以进行纵向扩展、横向扩展、两者都不进行扩展,或者两者都进行扩展。例如,应用程序的某些部分可能只进行纵向扩展,而其他部分可能同时进行横向扩展。
水平和垂直扩展方法适用于任何资源,包括计算和数据存储。一旦实施了其中一种方法,扩展通常不需要更改应用程序逻辑。然而,将应用程序从垂直扩展转换为水平扩展通常需要进行重大更改。
垂直向上扩展
垂直向上扩展也称为垂直扩展或向上扩展。其主要思想是通过硬件升级来提升单个节点的容量。这可能包括增加内存、增加 CPU 核心数或其他单节点变更。
历史上,由于其适用范围广、风险和复杂性(通常)较低,以及与算法改进相比硬件升级成本相对较低,垂直向上扩展一直是扩展中最常见的方法。垂直向上扩展同样适用于独立应用程序(例如桌面视频编辑、高端视频游戏和移动应用)以及基于服务器的应用程序(例如 Web 应用程序、分布式多人游戏以及连接到后端服务以进行繁重计算(例如地图和导航)的移动应用)。
然而,无法保证一定存在或能够负担得起足够强大的硬件。即使拥有了硬件,软件对硬件的利用程度也会受到限制。
由于涉及硬件变更,这种方法通常会导致停机。
横向扩展
横向扩展,也称为向外扩展或扩展出去,通过添加完整的节点来提升应用程序的整体容量。每个新增节点通常会增加等效的容量,例如相同的内存和相同的 CPU。
纵向扩展的架构挑战与横向扩展有所不同;其重点从最大化单个节点的性能转移到组合多个节点的性能。横向扩展往往比纵向扩展更复杂,并且对应用程序架构的影响更为根本。纵向扩展通常侧重于硬件和基础设施——我们“用硬件解决问题”——而横向扩展则侧重于开发和架构。根据所采用的扩展策略,责任可能落在不同部门的专家身上,这会使一些公司面临更复杂的问题。
为横向扩展而设计的应用程序通常会将节点分配给特定功能。例如,您可能拥有 Web 服务器节点和计费服务节点。当我们通过添加节点来增加整体容量时,我们添加的是用于特定功能的节点,例如 Web 服务器或计费服务;我们并非只是“添加一个节点”,因为节点配置与所支持的功能密切相关。
当支持特定功能的所有节点配置完全相同时——相同的硬件资源、相同的操作系统、相同的特定功能软件——我们称这些节点是同构的。
并非应用程序中的所有节点都是同构的,只有同一功能内的节点才是同构的。虽然 Web 服务器节点是同构的,计费服务节点也是同构的,但 Web 服务器节点不必与计费服务节点完全相同。
使用同构节点进行横向扩展是一种重要的简化。如果节点是同构的,那么基本的轮询负载均衡就能很好地工作,容量规划也更容易,编写自动缩放规则也更容易。如果节点可以不同,则需要更多上下文信息才能有效地分发请求。
在特定类型的节点(例如 Web 服务器)中,节点自主运行,彼此独立。一个节点无需与其他类似节点通信即可完成其工作。节点间资源协调程度会影响效率。
自主性至关重要,它能确保节点无论其他节点如何运作都能保持自身的效率。
横向扩展受限于新增节点的效率。最佳结果是每个新增节点都能带来相同数量的可用容量增量。
描述可扩展性
对应用程序可扩展性的描述通常只是简单地提及应用程序用户数量:“它可以扩展到 100 个用户”。更严谨的描述可能更有意义。请考虑以下定义:
- 并发用户数:在特定时间间隔(例如十分钟)内有活动的用户数量。
- 响应时间:用户发起请求(例如点击按钮)到收到往返响应之间的时间。
响应时间会因用户而异。一个有意义的描述可以将并发用户数和响应时间结合起来,作为衡量系统整体可扩展性的指标。
这是一个好的开始,但并非所有应用程序功能对系统资源的影响都相同。应用程序会使用多种功能:首页浏览、图片上传、观看视频、搜索等等。有些功能可能影响较小(例如首页浏览),而另一些功能则影响较大(例如图片上传)。平均而言,低影响应用占比可能为 90%,高影响应用占比可能为 10%,但这种比例也会随时间变化。
应用程序的用户类型也可能有所不同。例如,有些用户可能直接通过 Web 浏览器与您的 Web 应用程序交互,而另一些用户可能通过原生移动应用程序间接交互,这些应用程序通过程序接口(例如 REST 服务)访问资源。其他因素也可能相关,例如用户的位置或他们使用的设备的性能。记录实际的功能和资源使用情况有助于随着时间的推移改进此模型。
以上措施有助于制定应用程序的可扩展性目标,或为付费用户制定更正式的服务级别协议 (SLA)。
扩展单元
横向扩展时,我们会添加同质节点,尽管这些节点可能属于多种类型。扩展单元的容量是可预测的,理想情况下,它与可支持的特定应用程序功能相匹配。例如,每 100 个用户可能需要 2 个 Web 服务器节点、1 个应用程序服务节点和 100 MB 的磁盘空间。
这些需要一起扩展的资源组合称为扩展单元。扩展单元是一个有用的建模概念,例如在自动缩放模式(第 4 章)中。
对于业务分析而言,将可扩展性目标与按扩展单元组织的资源需求相结合,有助于制定成本预测。
资源争用限制可扩展性
可扩展性问题本质上是资源争用问题。限制可扩展性的并非并发用户数量本身,而是对 CPU、内存和网络带宽等有限资源的竞争性需求。资源不足以满足每个用户的需求,必须共享。这会导致部分用户速度变慢或被阻塞。这些被称为资源瓶颈。
例如,如果我们拥有高性能的 Web 服务器和数据库服务器,但网络连接带宽不足以应对流量需求,那么资源瓶颈就是网络连接。应用程序受限于其无法足够快速地通过网络传输数据。
为了突破当前的瓶颈,我们需要降低对资源的需求或增加其容量。为了缓解网络带宽瓶颈,在传输数据之前对其进行压缩可能是一个有效的方法。
当然,消除当前的瓶颈只会暴露下一个瓶颈。如此循环往复。
缓解资源争用
缓解资源争用有两种方法:一是降低资源消耗速度,二是增加资源。
应用程序对资源的利用效率可能高也可能低。由于规模受限于资源争用,因此,如果优化应用程序,使其更有效地利用可能成为瓶颈的资源,就能提高可扩展性。例如,优化数据库查询可以提高资源效率(更不用说性能了)。这种效率的提升使我们能够每秒处理更多事务。我们称之为算法改进。
效率的提升往往需要权衡。压缩数据可以更有效地利用网络带宽,但会降低 CPU 利用率和内存占用。务必确保消除一个资源瓶颈不会引入另一个瓶颈。
另一种方法是改进硬件。我们可以升级移动设备以获得更大的存储空间。我们可以将数据库迁移到更强大的服务器,从而受益于更快的 CPU、更大的内存以及更大更快的磁盘驱动器。摩尔定律(Moore's Law) 简洁地阐述了计算机硬件性能大约每隔几年就会翻一番,它完美地解释了为什么硬件性能能够持续提升。我们称之为硬件改进。
算法改进和硬件改进都能帮助我们突破性能极限,但都存在一定的局限性。算法改进的局限性在于我们能否巧妙地设计出更有效地利用现有硬件资源的新方法。算法改进的实施可能成本高昂、风险巨大且耗时。硬件改进的实施通常比较简单,但最终会受到现有硬件性能的限制。你可能需要的硬件价格可能高得令人望而却步,甚至根本无法获得。
当我们想不出任何新的算法改进方案,而硬件改进又无法快速实现时,该怎么办?这取决于我们的扩展方式。如果我们采用垂直扩展的方式,可能会陷入困境。
可扩展性是企业关注的重点
网站速度快对企业大有裨益。Compuware 对 33 家大型零售商的 1000 万次首页浏览量进行分析后发现,页面加载时间每延迟 1 秒,转化率就会下降 7%。谷歌观察到,页面响应时间每延迟 500 毫秒,流量就会下降 20%;雅虎观察到,延迟 400 毫秒会导致流量下降 5% 至 9%。亚马逊报告称,延迟 100 毫秒会导致零售收入下降 1%。谷歌已开始将网站性能作为搜索引擎排名的一个指标。(统计数据来源见附录 A。)
许多公司通过提升网站速度提高了客户满意度和收入,这样的例子不胜枚举;但也有更多案例表明,由于网站无法应对激增的流量,导致网站崩溃,最终以彻底失败告终。人为失误时有发生,例如大型零售商在没有做好充分准备的情况下就宣传线上促销活动(这种情况在美国感恩节后的星期一经常发生,这一天是著名的网络购物日)。类似的失误也出现在超级碗广告中。
云原生应用
本书旨在构建云原生应用,因此明确定义该术语至关重要。首先,我们将阐述云平台的假定特性,这些特性是云原生应用的基础。然后,我们将介绍基于此类平台,并运用本书中包含的模式和理念构建的云原生应用的预期特性。
云平台定义
云平台的以下特性使得云原生应用成为可能:
- 云平台拥有(看似)无限的资源,但受限于单个虚拟机的最大容量,因此云平台可以横向扩展。
- 云平台采用短期资源租赁模式,资源的释放与添加一样便捷。
- 云平台采用按需付费模式,云应用只需为当前分配的资源付费,所有使用成本透明公开。
- 云平台支持自助式、按需式、程序化的资源配置和释放,因此云平台可以实现自动化扩展。
- 云平台运行在通用硬件上的多租户服务既是其优势也是劣势,因此云应用更注重成本而非可靠性;故障是常态,但停机时间极少。
- 云平台拥有丰富的托管平台服务生态系统,例如虚拟机、数据存储、消息传递和网络服务,从而简化了云应用开发。
虽然这些特性在云之外并非不可能,但如果它们同时具备,则很可能是由云平台实现的。具体来说,Windows Azure 和 Amazon Web Services 具备所有这些特性。任何重要的云平台——无论是公有云、私有云还是其他类型的云——都将具备其中大部分特性。
本书中的模式适用于具备上述特性的平台,但其中许多模式也适用于仅具备部分特性的平台。例如,某些私有云可能没有按使用量付费的机制,因此按使用量付费可能并不完全适用。然而,相关的模式仍然可以用来降低总体成本,从而帮助公司节省资金,即使节省下来的资金不能直接用于特定的应用程序。
这些特性源自何处?已有公开证据表明,像 eBay、Facebook 和 Yahoo! 这样拥有庞大网络业务的公司都拥有具备类似功能的内部云,尽管这些证据并不总是足够详细。最好的证据来自三大巨头——亚马逊、谷歌和微软——它们都利用多年来运营自身高容量内部基础设施的经验,创建了可供其他公司以服务形式使用的公有云平台。
本书反复运用了这些特性。
云原生应用定义
云原生应用的架构旨在充分利用云平台。云原生应用应具备以下特性(如适用):
- 利用云平台服务构建可靠、可扩展的基础架构。(“让平台处理繁重的工作。”)
- 在松耦合架构中使用非阻塞异步通信。
- 可横向扩展,根据需求增加资源,根据需求减少资源。
- 优化成本以高效运行,避免资源浪费。
- 处理扩展事件,确保服务不中断或用户体验不下降。
- 处理瞬态故障,确保用户体验不下降。
- 处理节点故障,确保服务不中断。
- 利用地理分布最大限度地降低网络延迟。
- 无需停机即可升级。
- 通过主动和被动操作自动缩放。
- 即使节点频繁变更,也能监控和管理应用日志。
正如这些特性所示,应用程序无需支持数百万用户即可从云原生模式中获益。使用本书中的模式构建应用程序,即可得到云原生应用程序。采用这些模式的应用程序应比使用云服务但并非云原生的应用程序更具优势。例如,云原生应用程序应具有更高的可用性、更低的复杂性、更低的运营成本、更好的性能和更高的最大扩展能力。
Windows Azure 和 Amazon Web Services 是功能齐全的公有云平台,可用于运行云原生应用程序。然而,应用程序运行在 Azure 或 Amazon 上并不意味着它就是云原生应用程序。这两个平台都提供平台即服务 (PaaS) 功能,这无疑有助于开发者专注于云原生应用程序的逻辑,而不是底层架构。这两个平台也都提供基础设施即服务 (IaaS) 功能,为运行非云原生应用程序提供了极大的灵活性。但是,使用 PaaS 并不意味着应用程序就是云原生应用程序,使用 IaaS 也不意味着它就不是云原生应用程序。应用程序的架构及其平台使用方式是决定其是否为云原生应用程序的关键因素。
云原生应用程序并非适用于所有情况。通常情况下,从一开始就将新应用程序架构设计为云原生应用程序最具成本效益。将传统应用程序转换为云原生应用程序可能需要进行重大(且成本高昂)的更改,而收益可能不足以弥补成本。并非所有应用程序都应该是云原生应用程序,而且许多云应用程序也无需完全云原生。这是一个基于技术洞察的业务决策。
本书中的模式同样适用于那些并非完全云原生的云应用程序。
总结
可扩展性影响性能,而效率又影响可扩展性。两种常见的扩展模式是垂直扩展和水平扩展。垂直扩展通常更容易实现,但其局限性也比水平扩展更大。云原生应用采用水平资源分配,而可扩展性只是其优势之一。