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

1.3 快速和可扩展数据访问的构建块

在介绍了设计分布式系统时的一些核心考虑因素之后,我们现在谈谈困难的部分:扩展对数据的访问。

大多数简单的Web应用程序,例如LAMP堆栈应用程序,如图1.5所示。

               图1.5:简单的Web应用程序

随着它们的发展,存在两个主要挑战:扩展对应用服务器和数据库的访问。在高度可扩展的应用程序设计中,应用程序(或Web)服务器通常被最小化,并且通常体现为无共享体系结构。这使得系统的app服务器层可以水平扩展。由于这种设计,繁重的工作被压缩到数据库服务器和支持服务;在这一层,真正的扩展和性能挑战发挥作用。

本章的其余部分致力于通过提供对数据的快速访问,使这些类型的服务快速且可扩展的一些更常见的策略和方法。

         图1.6 过度简化的Web应用程序

大多数系统都可以简化为图1.6。这是一个很好的起点。如果您有大量数据,则需要快速方便地访问,例如在桌面的顶部抽屉中存放糖果。虽然过于简化,但之前的声明暗示了两个难题:存储的可扩展性和数据的快速访问。

为了本节的目的,我们假设您有许多TB的数据,并且您希望允许用户随机访问该数据的一小部分。 (参见图1.7。)这类似于在图像应用程序示例中在文件服务器上的某处定位图像文件。

                       图1.7 访问特定数据

这尤其具有挑战性,因为将TB的数据加载到存储器中可能非常昂贵。这直接转换为磁盘IO。从磁盘读取速度比从存储器读取慢很多倍,与Chuck Norris一样快,而磁盘访问速度比DMV速度慢。这种速度差异实际上增加了大数据集;实际上,对于顺序读取,内存访问速度比从磁盘读取快6倍,或者随机读取速度快10万倍(参见“大数据病理学”,http://queue.acm.org/detail。 CFM?ID = 1563874)。而且,即使有唯一的ID,解决知道在哪里找到这么少的数据的问题也是一项艰巨的任务。这就像试图从你的糖果藏匿中获取最后一个Jolly Rancher而不看。

值得庆幸的是,您可以使用许多选项来简化这一过程;其中四个比较重要的是缓存,代理,索引和负载均衡器。本节的其余部分讨论了如何使用这些概念中的每一个来更快地进行数据访问。

Caches

高速缓存利用了参考原理的局部性:可能再次请求最近请求的数据。它们几乎用于每个计算层:硬件,操作系统,Web浏览器,Web应用程序等。缓存就像短期内存:它具有有限的空间,但通常比原始数据源更快,并包含最近访问的项目。高速缓存可以存在于体系结构的所有级别,但通常位于最靠近前端的级别,在那里它们被实现为快速返回数据而不会对下游级别产生负担。

在我们的API示例中,如何使用缓存来加快数据访问速度?在这种情况下,有几个地方可以插入缓存。一种选择是在请求层节点上插入缓存,如图1.8所示

                            图1.8 在请求层节点上插入缓存

直接在请求层节点上放置缓存可以本地存储响应数据。每次向服务发出请求时,节点将快速返回本地缓存数据(如果存在)。如果它不在缓存中,请求节点将从磁盘查询数据。一个请求层节点上的缓存也可以位于内存(非常快)和节点的本地磁盘上(比进入网络存储更快)。

                  图1.9 多个缓存

将此扩展到多个节点时会发生什么?如图1.9所示,如果请求层扩展到多个节点,那么每个节点仍然可以拥有自己的缓存。但是,如果负载均衡器在节点之间随机分配请求,则相同的请求将转到不同的节点,从而增加了缓存未命中。克服这个障碍的两个选择是全局缓存和分布式缓存。

全局Cache

全局缓存就像它听起来一样:所有节点都使用相同的单个缓存空间。这涉及添加某种服务器或某种文件存储,比原始存储更快,并且可由所有请求层节点访问。每个请求节点以与本地节点相同的方式查询缓存。这种缓存方案可能会变得有点复杂,因为随着客户端和请求数量的增加,很容易压倒单个缓存,但在某些体系结构中非常有效(特别是那些使用这种全局缓存非常快速的专用硬件,或者有一个需要缓存的固定数据集)。

图中描述了两种常见的全局缓存形式。在图1.10中,当在缓存中找不到缓存响应时,缓存本身负责从底层存储中检索丢失的数据。在图1.11中,请求节点负责检索缓存中找不到的任何数据。

                                           图1.10 缓存负责检索的全局缓存

                           图1.11 请求节点负责检索的全局缓存

利用全局缓存的大多数应用程序倾向于使用第一种类型,其中缓存本身管理逐出和获取数据以防止来自客户端的相同数据的大量请求。但是,在某些情况下,第二种实现更有意义。例如,如果缓存用于非常大的文件,则低缓存命中百分比将导致缓存缓冲区因缓存未命中而变得不堪重负;在这种情况下,它有助于在缓存中占据总数据集(或热数据集)的大部分。另一个例子是一种架构,其中存储在缓存中的文件是静态的,不应该被驱逐。 (这可能是因为围绕数据延迟的应用程序要求 - 对于大型数据集,某些数据片段可能需要非常快 - 应用程序逻辑比缓存更好地理解驱逐策略或热点。)

分布式缓存

在分布式缓存中(图1.12),每个节点都拥有部分缓存数据,因此如果冰箱充当杂货店的缓存,分布式缓存就像将食物放在几个位置 - 冰箱,橱柜,和午餐盒 - 方便的地方,从没有去商店旅行取回小吃。通常,使用一致的散列函数来划分高速缓存,使得如果请求节点正在寻找某个数据片段,则它可以快速知道在分布式高速缓存中的哪个位置以确定该数据是否可用。在这种情况下,每个节点都有一小部分缓存,然后在转到源之前向另一个节点发送数据请求。因此,分布式缓存的一个优点是增加了缓存空间,只需将节点添加到请求池即可。


                                 图1.12:分布式缓存

分布式缓存的缺点是修复丢失的节点。一些分布式缓存通过在不同节点上存储多个数据副本来解决这个问题。但是,您可以想象这种逻辑如何快速复杂化,尤其是在您从请求层添加或删除节点时。虽然即使节点消失并且部分缓存丢失,但请求只会从原点拉出 - 所以它不一定是灾难性的!

关于缓存的好处在于它们通常会使事情变得更快(当然,正确实现!)您选择的方法只允许您更快地处理更多请求。然而,所有这些缓存都需要维持额外的存储空间,通常是昂贵的内存;没有什么是免费的高速缓存非常适合于使事情变得更快,而且在高负载条件下提供系统功能,否则将导致完全的服务降级。

流行的开源缓存的一个例子是Memcached(http://memcached.org/)(它可以作为本地缓存和分布式缓存工作);但是,还有许多其他选项(包括许多特定于语言或框架的选项)。

Memcached用于许多大型网站,即使它非常强大,它只是一个内存中的键值存储,针对任意数据存储和快速查找进行了优化(O(1))。

Facebook使用几种不同类型的缓存来获取其网站性能(请参阅“Facebook缓存和性能”)。他们在语言级别使用$ GLOBALS和APC缓存(以函数调用为代价在PHP中提供),这有助于使中间函数调用和结果更快。 (大多数语言都有这些类型的库来提高网页性能,它们几乎总是被使用。)Facebook然后使用分布在许多服务器上的全局缓存(参见“在Facebook上扩展memcached”),这样一个函数调用访问缓存可以为存储在不同Memcached服务器上的数据并行发出许多请求。这使他们可以为其用户配置文件数据获得更高的性能和吞吐量,并且有一个更新数据的中心位置(这很重要,因为当您运行数千台服务器时,缓存失效和维护一致性可能具有挑战性)。

现在让我们谈谈当数据不在缓存中时该怎么做......

 

原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值