可扩展的Web架构和分布式系统设计(一)

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:19   1582   0

开源软件已成为一些最大网站的基本构建块。随着这些网站的发展,围绕其架构的最佳实践和指导原则已经出现。本章旨在介绍设计大型网站时需要考虑的一些关键问题,以及用于实现这些目标的一些构建模块。

本章主要关注Web系统,尽管某些材料也适用于其他分布式系统。

1.1 Web分布式系统设计原理

构建和运营可扩展的网站或应用程序到底意味着什么?在原始层面,它只是通过Internet将用户与远程资源连接起来 - 使其可扩展的部分是资源或对这些资源的访问分布在多个服务器上。

像生活中的大多数事情一样,在构建Web服务时花时间提前计划可以帮助长远;了解大型网站背后的一些考虑因素和权衡可以在创建较小的网站时做出更明智的决策。以下是影响大型Web系统设计的一些关键原则:

  • 可用性:网站的正常运行时间对许多公司的声誉和功能至关重要。对于一些较大的在线零售网站而言,连续几分钟都无法使用可能导致数千或数百万美元的收入损失,因此设计他们的系统始终可用且对故障具有弹性是一项基本业务和技术要求。分布式系统中的高可用性要求仔细考虑关键组件的冗余,部分系统故障时的快速恢复以及出现问题时的优雅降级。
  • 性能:网站性能已成为大多数网站的重要考虑因素。网站的速度会影响使用率和用户满意度,以及搜索引擎排名,这是与收入和保留直接相关的因素。因此,创建一个针对快速响应和低延迟进行优化的系统是关键。
  • 可靠性:系统需要可靠,以便对数据的请求将始终返回相同的数据。如果数据更改或更新,则相同的请求应返回新数据。用户需要知道,如果某些内容被写入系统或存储,它将持续存在并且可以依赖于将来的检索。
  • 可伸缩性:当涉及到任何大型分布式系统时,大小只是需要考虑的规模的一个方面。同样重要的是增加处理更大负载的容量所需的努力,通常称为系统的可扩展性。可伸缩性可以指系统的许多不同参数:它可以处理多少额外流量,添加更多存储容量的容易程度,甚至可以处理多少个事务。
  • 可管理性:设计易于操作的系统是另一个重要的考虑因素。系统的可管理性等同于操作的可扩展性:维护和更新。可管理性需要考虑的事项是在出现问题时易于诊断和理解问题,易于进行更新或修改,以及系统操作的简单性。 (即,它是否经常运行而没有失败或例外?)
  • 成本:成本是一个重要因素。这显然可能包括硬件和软件成本,但考虑部署和维护系统所需的其他方面也很重要。系统构建所需的开发人员时间,运行系统所需的操作工作量,甚至所需的培训量都应予以考虑。成本是总拥有成本。

这些原则中的每一个都为设计分布式Web架构的决策提供了基础。然而,它们也可能彼此不一致,因此实现一个目标是以另一个目标为代价的。一个基本的例子:选择通过简单地添加更多服务器(可扩展性)来解决容量可能会以可管理性(您必须运行额外的服务器)和成本(服务器的价格)为代价。

在设计任何类型的Web应用程序时,重要的是要考虑这些关键原则,即使它是要承认设计可能会牺牲其中的一个或多个。

1.2 基础

在系统架构方面,有几点需要考虑:正确的部分是什么,这些部分如何组合在一起,以及什么是正确的权衡。在需要之前投资扩展通常不是一个明智的商业主张;然而,对设计的一些预见可以在未来节省大量的时间和资源。

本节重点介绍几乎所有大型Web应用程序的核心因素:服务,冗余,分区和处理故障。这些因素中的每一个都涉及选择和妥协,特别是在上一节中描述的原则的背景下。为了详细解释这些,最好从一个例子开始。

示例:图像托管应用程序

在某些时候,您可能已经在线发布了一张图片。对于托管和提供大量图像的大型站点,构建具有成本效益,高可用性和低延迟(快速检索)的架构存在挑战。

想象一下这样一个系统,用户可以将他们的图像上传到中央服务器,并且可以通过网络链接或API请求图像,就像Flickr或Picasa一样。为简单起见,我们假设此应用程序有两个关键部分:将图像上载(写入)到服务器的能力,以及查询图像的能力。虽然我们当然希望上传效率很高,但我们最关心的是当有人请求图像时能够非常快速地传送(例如,可以请求网页或其他应用程序的图像)。这与Web服务器或内容交付网络(CDN)边缘服务器(服务器CDN用于在许多位置存储内容,因此内容在地理上/物理上更接近用户,导致更快的性能)可能提供的功能非常相似。

该系统的其他重要方面是:

  • 对于要存储的图像数量没有限制,因此需要考虑存储可扩展性,在图像数量方面。
  • 图像下载/请求需要低延迟。
  • 如果用户上传图像,则图像应始终存在(图像的数据可靠性)。
  • 系统应易于维护(可管理性)。
  • 由于图像托管的利润率不高,因此系统需要具有成本效益

图1.1:图像托管应用程序的简化架构图

在此图像托管示例中,系统必须具有可感知的快速,其数据可靠地存储,并且所有这些属性都具有高度可扩展性。构建此应用程序的小版本将是微不足道的,并且可以轻松地托管在单个服务器上;然而,这一章并不会引起人们的兴趣。让我们假设我们想要构建一些可以像Flickr一样大的东西。

服务

在考虑可扩展的系统设计时,它有助于解耦功能,并将系统的每个部分视为具有明确定义的接口的自己的服务。实际上,以这种方式设计的系统据说具有面向服务的体系结构(SOA)。对于这些类型的系统,每个服务都有自己独特的功能上下文,并且通过抽象接口(通常是另一个服务的面向公众的API)与该上下文之外的任何内容进行交互。

将系统解构为一组互补服务将这些部分的操作彼此分离。这种抽象有助于在服务,其底层环境和该服务的使用者之间建立清晰的关系。创建这些清晰的描述可以帮助隔离问题,但也允许每个部分彼此独立地扩展。这种面向服务的系统设计非常类似于面向对象的编程设计。

在我们的示例中,所有上传和检索图像的请求都由同一服务器处理;但是,由于系统需要扩展,因此将这两个功能分解为自己的服务是有意义的。

快进并假设该服务正在大量使用;这样的场景使得很容易看出写入时间有多长会影响读取图像所需的时间(因为它们的两个功能将竞争共享资源)。根据架构,这种影响可能很大。即使上传和下载速度相同(大多数IP网络都不是这样,因为大多数设计用于至少3:1的下载速度:上传速度比),通常会从缓存中读取读取文件,并且写入最终必须转到磁盘(并且可能在最终一致的情况下写入几次)。即使一切都在内存中或从磁盘(如SSD)读取,数据库写入几乎总是比读取慢。 (Pole Position,一个用于数据库基准测试的开源工具,http://polepos.org/和结果http://polepos.sourceforge.net/results/PolePositionClientServer.pdf。)。

这种设计的另一个潜在问题是像Apache或lighttpd这样的Web服务器通常对它可以维护的同时连接数量有一个上限(默认值大约为500,但可以更高),而在高流量时,写入可以快速消耗所有这些。由于读取可以是异步的,或者利用其他性能优化(如gzip压缩或分块传输编码),因此Web服务器可以更快地切换服务读取并在客户端之间切换,每秒快速提供比最大连接数更多的请求(使用Apache和最大连接数设置为500,每秒提供数千个读取请求并不罕见。另一方面,写入往往在上载期间保持开放连接,因此在大多数家庭网络上上载1MB文件可能需要1秒以上,因此Web服务器只能处理500个这样的同时写入。

图1.2:拆分读写

规划这种瓶颈可以很好地将图像的读写分解到自己的服务中,如图1.2所示。这允许我们独立地扩展每个(因为我们可能总是会比写作更多地阅读),但也有助于澄清每个点上发生的事情。最后,这将把未来的问题分开,这样可以更容易地进行故障排除和扩展问题,例如慢速读取。

这种方法的优点是我们能够独立地解决问题 - 我们不必担心在相同的上下文中编写和检索新图像。这两种服务仍然利用全局图像语料库,但是它们可以通过适当的服务方法(例如,排队请求或缓存流行图像 - 以下更多内容)自由优化自己的性能。从维护和成本的角度来看,每个服务可以根据需要独立扩展,这很好,因为如果它们被组合和混合,则可能无意中影响另一个服务的性能,就像上面讨论的场景一样。

当然,当您有两个不同的端点时,上述示例可以很好地工作(实际上这与几个云存储提供商的实现和内容交付网络非常相似)。有很多方法可以解决这些类型的瓶颈,每种方法都有不同的权衡。

例如,Flickr通过在不同的分片中分配用户来解决这个读/写问题,这样每个分片只能处理一定数量的用户,并且随着用户的增加,更多的分片被添加到集群中(参见Flickr缩放的演示文稿,http: //mysqldba.blogspot.com/2008/04/mysql-uc-2007-presentation-file.html)。在第一个示例中,根据实际使用情况(整个系统的读写次数)更容易扩展硬件,而Flickr随其用户群进行扩展(但强制假设用户具有相同的使用率,因此可以有额外的容量)。在前者中,其中一个服务的中断或问题会降低整个系统的功能(例如,没有人可以写文件),而使用Flickr的一个分片的中断只会影响这些用户。在第一个示例中,更容易跨整个数据集执行操作 - 例如,更新写入服务以包括新元数据或搜索所有图像元数据 - 而使用Flickr体系结构时,每个分片都需要更新或搜索(或者需要创建搜索服务来整理那些元数据 - 这实际上就是他们所做的事情。

当谈到这些系统时,没有正确的答案,但它有助于回到本章开头的原则,确定系统需求(大量读取或写入或两者,并发级别,跨数据集的查询,范围,种类等),对不同的替代方案进行基准测试,了解系统将如何失败,并对失败发生时制定可靠的计划。

冗余

为了优雅地处理故障,Web体系结构必须具有其服务和数据的冗余。例如,如果单个服务器上只存储一个文件副本,则丢失该服务器意味着丢失该文件。丢失数据很少是一件好事,处理它的常用方法是创建多个或多余的副本。

同样的原则也适用于服务。如果应用程序具有核心功能,则确保同时运行多个副本或版本可以防止单个节点发生故障。

在系统中创建冗余可以消除单点故障,并在危机中根据需要提供备用或备用功能。例如,如果在生产中运行同一服务的两个实例,并且一个实例出现故障或降级,则系统可以故障转移到正常副本。故障转移可以自动发生或需要手动干预。

服务冗余的另一个关键部分是创建无共享架构。利用这种架构,每个节点能够彼此独立地操作,并且没有中央“大脑”管理状态或协调其他节点的活动。这对可扩展性有很大帮助,因为可以在没有特殊条件或知识的情况下添加新节点。然而,最重要的是,这些系统中没有单点故障,因此它们对故障更具弹性。

例如,在我们的图像服务器应用程序中,所有图像都会在某处的另一块硬件上具有冗余副本(理想情况下,如果发生地震或数据中心火灾等灾难,则位于不同的地理位置),以及要访问的服务图像将是多余的,所有可能的服务请求。 (参见图1.3。)(负载平衡器是实现这一目标的好方法,但下面还有更多内容)。

图1.3:具有冗余的图像托管应用程序

分区

可能存在无法容纳在单个服务器上的非常大的数据集。也可能是操作需要太多计算资源,性能降低并且必须增加容量的情况。在任何一种情况下,您都有两种选择:垂直或水平缩放。

垂直扩展意味着向单个服务器添加更多资源。因此,对于非常大的数据集,这可能意味着添加更多(或更大)的硬盘驱动器,因此单个服务器可以包含整个数据集。在计算操作的情况下,这可能意味着将计算移动到具有更快CPU或更多内存的更大服务器。在每种情况下,垂直缩放是通过使单个资源能够自己处理更多来完成的。

另一方面,水平缩放是添加更多节点。在大数据集的情况下,这可能是存储数据集的部分的第二服务器,并且对于计算资源,这将意味着在一些额外节点上分割操作或加载。为了充分利用水平扩展,它应该作为系统体系结构的内在设计原则包含在内,否则修改和分离上下文以使其成为可能会非常麻烦。

在涉及水平扩展时,一种比较常见的技术是将服务分解为分区或分片。可以分布分区,使得每个逻辑功能集是分开的;这可以通过地理边界或其他标准来完成,例如非付费用户和付费用户。这些方案的优点是它们提供具有增加容量的服务或数据存储。

在我们的图像服务器示例中,用于存储图像的单个文件服务器可能被多个文件服务器替换,每个服务器包含其自己唯一的图像集。 (参见图1.4。)这样的体系结构将允许系统用图像填充每个文件服务器,在磁盘变满时添加额外的服务器。该设计需要一个命名方案,将图像的文件名绑定到包含它的服务器。可以从跨服务器映射的一致散列方案形成映像的名称。或者,可以为每个图像分配增量ID,以便当客户端请求图像时,图像检索服务仅需要维护映射到每个服务器的ID范围(如索引)

图1.4:具有冗余和分区的映像托管应用程序

当然,跨多个服务器分发数据或功能存在挑战。其中一个关键问题是数据局部性;在分布式系统中,数据越接近操作或计算点,系统的性能越好。因此,将数据分布在多个服务器上可能存在问题,因为在需要它的任何时候它可能不是本地的,迫使服务器在网络上执行昂贵的所需信息提取。

另一个潜在的问题是不一致的形式。当存在从共享资源(可能是另一个服务或数据存储)读取和写入的不同服务时,存在竞争条件的可能性 - 其中一些数据应该被更新,但是在更新之前发生读取 - 并且在那些情况下数据不一致。例如,在图像托管方案中,如果一个客户端发送了使用新标题更新狗图像的请求,将其从“狗”更改为“Gizmo”,但同时另一个客户端正在阅读,则可能发生竞争情况图片。在那种情况下,不清楚哪个标题“狗”或“Gizmo”将是第二个客户收到的标题。

分区数据肯定存在一些障碍,但分区允许将每个问题按数据,负载,使用模式等分成可管理的块。这有助于提高可扩展性和可管理性,但并非没有风险。有很多方法可以降低风险并处理故障;但是,为了简洁起见,本章不涉及它们。如果您有兴趣阅读更多内容,可以查看我的博客文章,了解容错和监控。

原文链接

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP