可扩展的Web架构和分布式系统设计(三)
代理
在基本级别,代理服务器是一个中间件硬件/软件,它接收来自客户端的请求并将它们中继到后端源服务器。通常,代理用于过滤请求,日志请求或有时转换请求(通过添加/删除标头,加密/解密或压缩)。
图1.13:代理服务器
在协调来自多个服务器的请求时,代理也非常有用,从系统范围的角度提供优化请求流量的机会。使用代理加速数据访问的一种方法是将相同(或类似)请求一起折叠为一个请求,然后将单个结果返回给请求客户端。这称为折叠转发。
想象一下,在几个节点上存在对相同数据的请求(让我们称之为littleB),并且该数据不在缓存中。如果该请求被认为是代理路由,那么所有这些请求都可以折叠成一个,这意味着我们只需要读取一次offB。 (参见图1.14。)这种设计会产生一些成本,因为每个请求的延迟可能略高,有些请求可能会稍微延迟,以便与类似的请求分组。但它会提高高负载情况下的性能,特别是在反复请求相同数据时。这类似于缓存,但它不是像缓存那样存储数据/文档,而是优化对这些文档的请求或调用,并充当这些客户端的代理。
例如,在LAN代理中,客户端不需要自己的IP来连接到Internet,LAN将折叠来自客户端的相同内容的呼叫。这里很容易混淆,因为许多代理也是缓存(因为它是放置缓存的一个非常合理的位置),但并非所有缓存都充当代理。
图1.14:使用代理服务器来折叠请求
使用代理的另一个好方法是不仅崩溃对相同数据的请求,而且还折叠对原始存储中空间上靠近的数据的请求(连续地在磁盘上)。采用这种策略可以最大化请求的数据位置,从而减少请求延迟。例如,假设一堆节点请求B的部分:partB1,partB2等。我们可以设置我们的代理来识别各个请求的空间局部性,将它们折叠成单个请求并仅返回bigB,从而大大减少了从数据源读取。 (参见图1.15。)当您随机访问跨TB数据时,这会对请求时间产生很大影响!代理在高负载情况下或缓存有限时特别有用,因为它们实际上可以将多个请求合并为一个。
图1.15:使用代理来折叠空间上靠近的数据请求
值得注意的是,您可以将代理和缓存一起使用,但通常最好将缓存放在代理服务器前面,原因与最好让速度较快的跑步者在拥挤的马拉松比赛中首先启动一样。这是因为缓存是从内存提供数据,它非常快,并且不介意对同一结果的多个请求。但是如果缓存位于代理服务器的另一端,那么缓存之前的每个请求都会有额外的延迟,这可能会影响性能。
如果您正在考虑向系统添加代理,可以考虑许多选项; Squid和Varnish都经过道路测试,并广泛用于许多生产网站。这些代理解决方案提供了许多优化,以充分利用客户端 - 服务器通信。在Web服务器层安装其中一个作为反向代理(在下面的负载平衡器部分中说明)可以显着提高Web服务器性能,减少处理传入客户端请求所需的工作量。
索引
使用索引快速访问数据是优化数据访问性能的众所周知的策略;可能是最知名的数据库。索引使得存储开销增加和写入速度变慢(因为您必须同时写入数据并更新索引)以获得更快的读取。
就传统的关系数据存储而言,您也可以将此概念应用于更大的数据集。使用索引的技巧是您必须仔细考虑用户将如何访问您的数据。在数据集大小为TB但具有非常小的有效载荷(例如,1KB)的情况下,索引是优化数据访问的必要条件。在如此大的数据集中查找小的有效载荷可能是一个真正的挑战,因为您无法在任何合理的时间内迭代那么多的数据。此外,这么大的数据集很可能分布在几个(或许多!)物理设备上 - 这意味着您需要某种方法来找到所需数据的正确物理位置。索引是执行此操作的最佳方式。
图1.16:索引
索引可以像目录一样使用,引导您到达数据所在的位置。例如,假设您正在寻找一条数据,B部分的第2部分 - 您如何知道在何处找到它?如果您有一个按数据类型排序的索引 - 比如数据A,B,C-它会告诉您原点数据B的位置。然后你只需要寻找那个位置并阅读你想要的B部分。 (见图1.16。)
这些索引通常存储在内存中,或者存储在传入客户端请求的本地。 Berkeley DB(BDB)和树状数据结构通常用于在有序列表中存储数据,非常适合使用索引进行访问。
通常有许多索引层用作地图,将您从一个位置移动到下一个位置,依此类推,直到您获得所需的特定数据。 (见图1.17。)
图1.17:多层索引
索引还可用于创建相同数据的多个不同视图。对于大型数据集,这是定义不同过滤器和排序的好方法,而无需创建许多额外的数据副本。
例如,假设前面的图像托管系统实际上托管了图书页面的图像,并且该服务允许客户端查询这些图像中的文本,搜索关于某个主题的所有图书内容,就像搜索引擎允许您一样搜索HTML内容。在这种情况下,所有这些书籍图像都需要许多服务器来存储文件,并且找到一个要呈现给用户的页面可能有点牵扯。首先,需要易于访问查询任意单词和单词元组的反向索引;然后有一个挑战是导航到该书中的确切页面和位置,并检索结果的正确图像。因此,在这种情况下,反向索引将映射到位置(例如书B),然后B可以包含具有每个部分中的所有单词,位置和出现次数的索引。
可以在上图中表示Index1的倒排索引可能类似于以下内容 - 每个单词或单词元组提供了包含它们的书籍的索引。
Word(s) | Book(s) |
---|---|
being awesome | Book B, Book C, Book D |
always | Book C, Book F |
believe | Book B |
中间索引看起来很相似,但只包含书B的单词,位置和信息。这种嵌套索引体系结构允许每个索引占用的空间少于所有这些信息必须存储到一个大的反向索引中。
这对于大规模系统来说至关重要,因为即使是压缩,这些索引也会变得非常庞大且存储成本也很高。在这个系统中,如果我们假设我们拥有世界上很多书籍 - 100,000,000(参见Inside Google Books博客文章) - 并且每本书只有10页长(为了使数学更容易),每页250字,这意味着有2500亿字。如果我们假设每个字平均有5个字符,并且每个字符需要8位(或1个字节,即使某些字符是2个字节),那么每个字5个字节,那么只包含每个字一次的索引超过1TB存储。因此,您可以看到创建具有许多其他信息(如单词元组,数据位置和出现次数)的索引可以非常快速地加起来。
创建这些中间索引并以较小的部分表示数据会使大数据问题易于处理。数据可以分布在许多服务器上,并且仍可快速访问。索引是信息检索的基石,也是当今现代搜索引擎的基础。当然,本节仅涉及表面,并且正在进行大量研究,以便如何使索引更小,更快,包含更多信息(如相关性),并无缝更新。 (竞争条件存在一些可管理性挑战,以及添加新数据或更改现有数据所需的大量更新,特别是在涉及相关性或评分的情况下)。
能够快速,轻松地找到您的数据非常重要;索引是实现这一目标的有效而简单的工具。