您的当前位置:首页正文

构建高性能web架构和分布式系统

来源:帮我找美食网


构建高性能web架构和分布式系统

一、设计分布式系统需要考虑的核心要素: 1、可用性 2、性能 3、可靠性 4、可扩展 5、易管理 6、成本

二、可扩展的数据访问 1、负载均衡 2、代理 3、全局缓存 4、分布式缓存 三、

简单web应用程序面临的两大挑战:构建可扩展的应用程序服务器和数据访问机制

四、可扩展存储和快速的数据访问。

五、

六、提升数据访问速度的四大法宝

使用索引来快速访问和优化数据是一个众所周知的策略,最有名的莫过于数据库索引。

图16 索引

一个索引就是数据库表的目录,表中数据和相应的存储位置的列表。好比是一篇文章的目录,可以加 快数据表的。例如让我们来查找一块数据,B中的第二部分——如何发现它的位置?如果你通过数据类型存储了一个索引——例如数据A、B、C——它将告诉你数 据B的原始位置。然后你只需去查看B并且根据需要阅读B的数据即可(参考图16)。

这些索引通常存储在内存或者是传入客户端请求的本地中。Berkeley DBs(BDBs)和树数据结构常常被用在有序列表中存储数据,这是访问索引的理想选择。

通常,会把许多层索引作为一个映射,从一个位置移到下一个,以此类推,直到你得到想要的特定块数据(参照图17)。

图17 多层索引

索引也可以对相同的数据创建多个不同的视图。对大型数据集来说,这种方法是非常好的,无需创建多个额外的数据副本就可以定义不同的过滤和排序, 例如,早期的图像托管系统实际上是托管图像书本内容,允许客户端查询这些图像中的内容,输入一个主题,就可以把所有相关的内容搜索出来。此外,采用 同样的方式,搜索引擎还允许你搜索出HTML内容。在这种情况下,需要很多的服务器来存储这些文件,查找其中一个页面可能会很麻烦。首先,反向索引查询任 意个单词或字元祖都需要可以轻松地访问;再有就是导航到正确的页面和位置,检索到正确的图像结果也是项挑战。因此,在这种情况下,反向索引会映射到一个位 置(例如书B),然后书B可能会有一个包含所有内容、位置和各个部分出现次数的索引。

这种中间级索引只包含了Words、位置和书B的信息。与所有的信息不得不存储到一个大的反向索引中相比,这种嵌套的索引架构允许每个索引占用较少的空间。在大型系统中,这是非常关键的,即使采用压缩,这些索引也需要占用相当昂贵的存储空间。

例如,让我们假设这个世界上有——100,000,000本书(参考Inside Google Books官方博客)——每本书只有10页,每页只有250个单词,这也就意味着有2500亿个单词。如果每个单词只有5个字节,每个字节占用8 bits(或1个byte,甚至有些字符占用2 bytes),所以5 bytes/单词,那么一个索引所包含的单词就有可能超过一个TB的存储。此外,索引还有可能包含其他信息,例如元祖单词、数据位置等。

能够快速、轻松地找到数据是非常重要的,而使用索引就可以简单高效的实现。 负载均衡器

分布式系统的另一个关键部分是负载均衡。负载均衡器几乎是每个架构的主要组成部分,他们的角色是负责把网络请求分散到一个服务器集群中的可用服务器上去,通过管理进入的Web数据流量和增加有效的网络带宽,从而使网络访问者获得尽可能最佳的联网体验的硬件设备。

图18 负载均衡器

这里有许多种算法可用于为请求提供服务,包括随机选择一个节点、循环或者甚至是基于某个特定的标准来选择节点,例如内存或CPU利用率。负载均衡器即可以以硬件的方式表现出来,也可以以软件的方式。HAProxy是一个开源的负载均衡器,并且得到了非常广泛的使用。

在一个分布式系统中,负载均衡器通常处于系统的前端位置,所有传入的请求会相应地被路由。在一个复杂的分布式系统中,一个请求被路由到多个负载均衡器上并不常见,如图19所示:

图19 多个负载平衡器

和代理一样,有些负载均衡器也可以基于请求的类型路由到不同的服务器集群上。(技术上来讲,这也被称为反向代理。)

负载均衡器所面临的挑战之一是管理用户特有的会话(user-session-specific)数据。在一个电子商务网站上,当你只有一个客户端 时,是很容易让用户把商品放入购物车并且继续访问(这是非常重要的,因为商品很有可能在继续出售,而用户退出时,商品仍然留在购物车里)。然而,如果用户 本次会话路由了一个节点,那么当他下次访问的时候会路由一个不同的节点,这样,就很有可能使购物车里的商品不一致,因为新的节点有可能会丢失该用户购物车 里原先的商品(当你先放6包Mountain Dew 在购物车里,等到再次登录后发现购物车为空了)。解决这个问题的方法之一是使用sticky sessions,来使用户一直被路由到相同的节点,但它很难利用到可靠性功能,像自动故障转移(automatic failover)。这种情况下,用户的购物车里将会一直有商品,但如果sticky node变的不可用,这就需要特殊情况来处理并且假设购物车里的商品将不再有效(尽管希望这种假设不会被内置于应用程序里)。当然解决这个问题还有许多其 他方法,例如本文提到的服务以及不包括(浏览器缓存、cookies和URL重写)。

在一个大型系统里会有各种不同类型的调度和负载均衡算法,包括简单点的像随机选择或循环以及更复杂的机制,例如利用率和容量。所有的这些算法都可以 分布流量和请求,并且提供有用的可靠性工具,像自动故障转移或者自动清除一个坏的节点(例如当它无法响应时)。然而,这种高级功能会把问题诊断的复杂。 例如,当遇到高负载情况时,负载均衡器

将会移除变慢或超时的节点(因为请求太多,删除节点后会把请求分配到其他节点上),这无疑会加剧其他节点的工作量, 即负载加重。这种情况下,大量的监测变的非常重要,因为整个系统流量和吞吐量看起来可能会减少(因为节点服务更少的请求),但可能会累坏个别节点(处理更 多的请求)。

负载均衡器也是扩展系统容量的一种简单方式,像文中提到的其他技术,在分布式系统架构中发挥着非常重要的作用。负载均衡器也提供一些重要功能来测试节点的健康状况,例如,如果该节点响应迟钝或过载,它可能就会被删除,然后利用系统中不同的节点冗余。 队列

到目前为止,我们已经讨论了许多方法来加快数据读取速度,但扩展数据层的另一个重要组成部分是如何高效的写入数据。在简单的系统中,进程负载等都比 较少,并且数据库比较小,毋庸置疑,写的速度肯定不会慢。然而,在大型复杂的系统里,这个速度就很难把握了,可能会花费很长的时间。例如,数据有可能要写 到几个不同的地方,不同的服务器或索引、或者系统正处于高负载情况下。在这种情况,该在哪里进行写?或者其他任何任务都有可能花费很长时间,要想在系统实 现性能和可用性需要构建异步。处理这种异步的一种常见的方式就是采用队列。

图20 同步请求

想象在一个系统里,每个客户机都要把请求发送至远程服务器,那么服务器应该尽可能快的接收并完 成任务,然后把结果返回到相应的客户端。在小型系统中,一台服务器(或逻辑服务器)传入客户端数据会与客户端发出时一样快,这样就比较完美了。然而,当服 务器接收到的请求多余它的处理能力时,那么每个客户端必须排队等待服务器处理其他客户端请求,直到轮到你了,服务器才会处理你的请求,直到最终完成。这就 是一个同步请求的例子,如图20所示。

这种同步行为会严重降低客户端性能,客户端被迫等待,而通过添加额外的服务器来满足负载并不能解决问题,即使采用最有效的负载均衡也很难保证分配公 平,在大客户端下。进

一步讲,如果处理请求的服务器不可用或者瘫痪,那么客户端上游也将失败。有效的解决这个问题需要抽象客户端请求以及服务请求的实际工 作。

图21 使用队列来管理请求

队列就像听起来那样简单,一个任务进来,就添加到队列里去,然后the workers挑选有能力处理的下一个任务。(参考图21)这些任务有可能仅是简单的写入,也有可能是复杂的,如把文档生成图像预览。当一个客户端把任务 请求提交的队列中时,他们不需要被迫等待结果,相反,他们只需确认请求是否被正确接收。

队列使客户端能够以异步的方式工作,对客户端请求和响应提供战略抽象。另一方面,在一个同步系统中,请求和回应是没有分化的,因此他们不能被分开管 理。在异步系统中,客户端发出请求任务,服务器对收到的消息进行响应并确认任务被接收,然后客户端可以定期检查任务状态,一旦任务完成,即可看到结果。当 客户端在等待异步请求是否完成时,它还可以自由执行其他任务,甚至是向其他服务器发出异步请求。下面要介绍的是消息和队列在分布式系统中的杠杆作用。

队列也对服务中断或失败提供一种保护机制。例如,它很容易创建一个高度健壮的队列,当服务器瞬间失败时,该队列可以把刚刚失败的请求重新发送至服务器。相比直接暴露客户端来间断服务供应,使用队列来保证服务质量更可取,要求必须有复杂且矛盾性的客户端差错处理。

队列是管理分布式通信与任何大规模分布式系统中各个部分之间的基础,并且有许多实现方式。这里有许多开源的队列,如RabbitMQ、ActiveMQ、BeanstalkD,但也有一些当做服务使用,如Zookeeper,甚至是用来数据存储,像Redis。

文章鸣谢:煤气发生炉.

因篇幅问题不能全部显示,请点此查看更多更全内容

Top