构建可扩展分布式系统:方法与实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.1 系统架构基础

几乎所有大规模系统都是从小规模开始,在成功路上逐渐发展壮大。从Ruby on Rails、Django或类似的开发框架开始架构系统是常见且明智的做法,它们可以加速开发,使系统得以快速启动并运行。基于一个典型且简单的软件架构来启动你的系统开发,与采用快速开发框架获得的效果相似,如图2-1所示。此架构包括客户端层、应用服务层和数据库层。如果你使用Rails或类似产品,那么可以直接获得以下便利:内置了处理Web应用程序的MVC(模型-视图-控制器)模式和生成SQL查询的ORM(对象-关系映射器)。

使用上述架构,用户从移动应用程序或Web(网页)浏览器向系统提交请求。互联网网络的魔力(参见第3章)将请求传递给运行在企业或商业云数据中心的机器上的应用服务。通信使用标准的应用层网络协议,通常是HTTP。

图2-1:简单的多层分布式系统架构

应用服务运行了API的代码,支持客户端发送的HTTP请求。收到请求后,服务会执行与请求的API关联的代码。在此过程中,可能会读取数据库的数据,或写入数据库,或写入其他外部系统,具体取决于API的语义。请求完成后,服务会将结果发送回客户端,结果在客户端应用程序或浏览器中显示。

许多系统在概念上看起来与上述描述一致。应用服务代码利用服务器执行环境,同时处理来自多个用户的多个请求。应用服务器技术有无数种——例如,Java EE和Java的Spring框架,Python的Flask(https://oreil.ly/8FYu5)——它们在上述场景中被广泛使用。

这种方法通常会产生所说的单体架构[1]。随着应用程序的特性变得更加丰富,单体应用程序的复杂性往往会增加。所有API处理程序都内置在同一个服务器代码中,最终会让快速修改和测试变得困难。由于所有API实现都在同一个应用服务中运行,执行足迹可能变得极其繁杂。

尽管如此,如果请求的负载压力保持较低的水平,则此应用程序架构足够了,服务足以处理请求并保持低延迟。如果请求负载持续增长,则意味着延迟增加,因为服务没有足够的CPU和内存来同时处理大量的并发请求,请求将需要等待更长的时间。在这种情况下,单台服务器已经超载,成了性能瓶颈。

对于上述案例,第一个扩展策略通常是“扩展”应用服务的硬件。假设你的应用程序运行在AWS上,你可以将服务器从带有四个CPU(虚拟)和16 GB内存的普通t3.xlarge实例升级到t3.2xlarge实例,为应用程序提供翻倍的CPU和可用内存[2]

扩展很简单,它使现实世界的许多应用程序在支持更大的工作负载方面取得了长足的进步。显然,扩展硬件要花更多的钱,但也物有所值,扩展后的系统满足了你的实际需求。

然而,不可避免的是,对于许多应用程序,无论你拥有多少CPU和多少内存,负载都将增长到超出单个服务器节点所能服务的范围。这时你需要一个新的策略,即第1章提及的,横向扩展或水平扩展[3]