将网站设计为高度可扩展的最佳方法是什么?


35

对于需要高度可扩展性的网站(例如Facebook之类的社交网络),设计网站的最佳方法是什么?

  1. 我是否应该具有网站查询的Web服务以获取所需的数据?

    要么

  2. 该网站应该直接查询数据库吗?(可以使用内置的语言构造来自动填充表格等)。

我认为Web服务是更好的设计,因为它提供了集中的数据访问,并且诸如缓存之类的东西变得更易于控制,但是其他人怎么看?


还有一个问题是要使用哪种架构(例如MVC等)。
伊凡

在不知道将要启动什么的情况下,很难给出答案,但是请记住“云服务”,您的应用程序可能适合某种SaaS应用程序。(它是集中的)。
deepcell 2011年

一般来说,我会说,没什么特别的
丹尼尔

1
在“云”中构建它,并花费大量时间阅读HighScalability.com。
Evan Plaice 2012年

Answers:


37

哇,这是一个简单的问题,有很多可能的答案。您问题的最明确的部分是询问它是否具有更大的可伸缩性以直接或通过Web服务与数据库交互。答案很简单:直接查询数据库。通过Web服务增加了一大堆延迟,这对于在防火墙后运行的代码(大体而言)完全是不必要的。例如,Web服务需要某些组件来接收请求,反序列化,查询数据库,序列化响应并返回请求。因此,如果您的代码都在防火墙后面运行,请省去麻烦,直接查询数据库。

但是,使网站具有可伸缩性远远超出了您最初提出的问题。因此,如果我在这里切线,请原谅我,但我认为考虑到您特别提到Facebook可能会很有用。

我建议您阅读Brad Fitzpatrick(LiveJournal的创始人,现在是Google)创建的工作和工具。当我与他在“六人公寓”工作时,这里有一些我从他那里学到的东西,以及有关LiveJournal使其可扩展的体系结构的知识。

  1. 使用窄数据库表而不是宽数据库表。令人着迷的是学习促使该体系结构发展的因素,该体系结构创建了一个轻松,快速的系统升级。如果使用宽表或表中每个字段或属性都是表中的一列的表,那么当需要升级数据库模式时(例如添加新列),系统将需要在表模式下锁定表更改已实施。大规模运行时,这意味着对数据库架构的简单更改可能会导致大型数据库中断。显然很烂。另一方面,窄表仅将与对象关联的每个单独属性存储为数据库中的一行。因此,当您要将新列添加到数据库时,您要做的就是将记录插入表中,这是非锁定操作。好的,这是一个背景知识,让我们看看该模型如何在像LiveJournal这样的工作系统中实际转换。

    假设您要在一个人的博客上加载最近的10个日记条目,并且假设每个日记条目都有10个属性。在经典的宽表布局中,每个属性都将与表上的一列相关。然后,用户将查询该表一次以获取所需的所有数据。该查询将返回10行,每行将具有所需的所有数据(例如SELECT * FROM条目ORDER BY日期LIMIT 10)。在狭窄的表格布局中,情况有所不同。在此示例中,实际上有两个表:第一个表(表A)存储一个简单的条件,用户可以根据该条件进行搜索,例如,条目的ID,作者的ID,条目的日期等。第二个表(表B)然后存储与条目关联的所有属性。第二个表具有三列:entry_id,键和值。对于表A中的每一行,表B中将有10行(每个属性一行)。因此,为了获取并显示最后十个条目,您将需要11个查询。第一个查询为您提供条目ID列表,然后接下来的十个查询将获取与第一个查询中返回的每个条目关联的属性。

    “天哪!” 您说:“这在地球上怎么可以扩展?!” 它完全违反直觉吗?在第一种情况下,我们只有一个数据库查询,但是在第二种“更具扩展性”的解决方案中,我们有11个数据库查询。这是没有意义的。该问题的答案完全取决于下一个项目符号。

  2. 自由使用内存缓存。如果您不知道,memcache是​​一个分布式,无状态,低延迟,基于网络的缓存系统。Facebook,Google,Yahoo以及地球上几乎所有流行且可扩展的网站都使用它。它是Brad Fitzpatrick发明的,部分目的是帮助抵消窄表数据库设计中固有的数据库开销。让我们看一下与上面#1中讨论的示例相同的示例,但是这次,我们介绍内存缓存。

    让我们从用户首次访问页面而缓存中没有内容开始。首先,查询表A,该表返回要在页面上显示的10个条目的ID。然后,对于每个条目,您都查询数据库以检索与该条目关联的属性,然后使用这些属性构成一个您的代码可以与之交互的对象(例如,一个对象)。然后,您将该对象(或该对象的序列化形式)存储在内存缓存中。

    某人第二次加载同一页面时,您将以相同的方式开始:通过在表A中查询要显示的条目ID列表。对于每个条目,您首先要进入内存缓存并说:“缓存中是否有条目#X?” 如果是,则memcache将入口对象返回给您。如果不是,则需要再次查询数据库以获取其属性,构成对象并将其存储在内存缓存中。在大多数情况下,第二次有人访问同一页面时,只有一个数据库查询,然后直接从内存缓存中提取所有其他数据。

    实际上,大多数LiveJournal最终发生的事情是,系统的大多数数据(尤其是易失性数据)已缓存在内存缓存中,而支持窄表模式所需的数据库额外查询几乎完全被抵消了。

    这种设计使解决与将与所有朋友相关联的帖子列表组装到信息流或“墙”中的问题变得非常容易。

  3. 接下来,考虑对数据库进行分区。上面讨论的模型还存在另一个问题,那就是您的窄表往往会很大/很长。这些表的行越多,其他管理任务就越难。为了弥补这一点,通过以某种方式对表进行分区来管理表的大小可能是有意义的,这样一个数据库可以为用户群集提供服务,而另一个数据库可以为另一个用户群集提供服务。这可以分配数据库负载,并保持查询效率。

  4. 最后,您需要很棒的索引。查询的速度将在很大程度上取决于数据库表的索引程度。我不会花太多时间来讨论什么是索引,只是要说它就像是一个巨大的卡片目录系统,可以使在大海捞针中的查找效率更高。如果使用mysql,则建议打开慢查询日志以监视需要很长时间才能完成的查询。当查询突然出现在您的雷达上时(例如,因为它很慢),请找出需要添加到表中的索引以加快查询速度。

“感谢您提供所有这些出色的背景知识,但是,圣洁的家伙,我将不得不编写很多代码。”

不必要。已经编写了许多库,这些库使与Memcache的接口变得非常容易。还有其他库将上述整个过程编入了代码;Perl中的Data :: ObjectDriver就是这样一个库。至于其他语言,则需要进行自己的研究。

希望这个答案对您有所帮助。我经常发现,系统的可伸缩性通常会越来越少地归因于代码,而越来越多地归因于可靠的数据存储和管理策略/技术设计。


3
+1我真的很喜欢这个哇,这是一个简单的问题,其中包含许多可能的答案。
Pankaj Upadhyay

1
我完全不同意“直接查询数据库”。您提到要对数据库进行分区以提高性能,因为使用API​​接口更容易实现单主机多从机体系结构。将数据库与应用程序分离的好处是,API层可以根据需要分发请求。API是一种抽象,允许您更改基础实现和/或重用数据而不会破坏应用程序。
Evan Plaice 2012年

1
(续)序列化总是会增加开销,但只会在API层增加开销,而API层很可能由同时运行的多个实例组成。如果您担心跨网传输速度,请转换为JSON,无论如何它很可能会用gzip压缩。将工作从服务器推送到客户端时,可以发现最简单的性能提升。要问的重要问题是,您是要在应用程序内还是在服务器级分发请求?哪个更容易复制?
Evan Plaice 2012年

1
@EvanPlaice-关于重用性和使用服务时更改服务逻辑实现的要点。此外,服务还可以使用缓存基础结构代替直接数据库调用。
Ashish Gupta

1
@AshishGupta确实,将数据分区到单独服务的唯一区别是用户收到的内容。而是在服务器上组装html +内容。用户分别接收数据和html,并且客户端浏览器处理重组。通过将数据作为单独的服务,还可以将其用于移动应用程序或其他非基于Web的客户端(例如智能电视应用程序)。
Evan Plaice 2015年

13

对于诸如Facebook之类的社交网络之类的需要高度可扩展的网站,设计网站的最佳方法是什么?

测量。

我想...

错误的政策。

需要实际测量。


定量指标FTW。
bhagyas

1
好的...测量后会怎样?
Pacerier 2014年

9

可扩展性不是特定实施策略的功能,而是设计您的应用程序体系结构,以便数据访问层可以在不进行大量重构和重写的情况下发展。

构建可扩展系统的一项重要技术是了解您的高级数据访问需求并围绕它们建立接口协定。例如,您可能需要获得一位用户列出任何用户最近发布的50张照片

您的应用程序业务逻辑和数据访问逻辑之间不一定需要网络通道。一个方法调用间接调用每个逻辑操作一个方法就可以很好地启动。

首先,使这些数据访问方法尽可能简单。在您的应用程序提供实际使用模式并且收集有关瓶颈所在的数据之前,很难预测性能问题的根源。

通过具有定义良好的数据访问界面,您可以改进数据访问实现,而无需对整个应用程序进行大范围更改。您还可以决定透明地切换到业务逻辑的Web服务体系结构。

上面的许多答案在发现性能瓶颈后就如何进行提供了一些很好的建议,但是如果过早应用这些性能瓶颈,您可能会在代码复杂性变得烦恼之前就知道是否需要复杂性。


4

开发一个简单的网站,使其达到一定的访问量水平。您将学习如何制作可扩展的网站。

在面对问题之前,您将无法想到解决方案

一旦站点滚动并且面临扩展需求,请相信我,您一定会知道该怎么做。:-)


好报价!!!!!!!!!!
阿米尔·侯赛因'17

2

众所周知,默认情况下,Web应用程序应设计为三层:Web(表示)层,应用程序层和数据库层。这种划分是由于每个层的要求不同-通常是数据库的高质量磁盘访问/存储,应用程序层的CPU /内存高以及Web层的外部带宽/内存/地理位置分散高。应用程序/数据库层通常合并到一个应用程序中,直到应用程序生命周期中的更晚为止,因为数据库计算机通常倾向于大型服务器,这些服务器也可以构建为处理早期应用程序负载。

但是,您的应用程序的特定层数和适当的体系结构不必与此模型或任何其他模型匹配。

计划需要测量和监视系统中的所有活动。从两层或三层设计开始,并专注于在构建时看起来需要最多资源的部分。让运行中的应用程序在此级别指导您的设计。您收集的信息越多,信息越准确和详细,就可以随着应用程序的增长做出更好的决策。

选择一个框架和体系结构,以后将允许您尽可能快地,轻松地进行/更改所需的更改。即使在同一个可执行文件中执行数据访问/存储/处理和应用程序处理,但是如果将它们适当地考虑在内,那么以后将它们分成两层也不会那么困难。


2

连接数据库的任何其他步骤都只是开销。例如,在UI -> Business Facade -> Business -> Data Access -> Database和之间UI -> Database,第二种方法更快。但是,删除的步骤越多,系统的可维护性就越差,并且重复出现的次数也就越多。想象一下编写必要的代码来检索个人资料,主页,朋友管理页面等中的朋友列表。

因此,您应该在更高的性能(当然会直接影响更高的可伸缩性)和更好的可维护性之间取得平衡。

但是,当您考虑创建高度可扩展的网站时,不要局限于数据库连接主题。也请考虑以下事项:

  1. 选择正确的平台(PHP具有脚本特性,因此速度更快,但是ASP.NET需要动态编译所请求的文件以处理该文件并提供服务。此外,由于它的回调node.js也被称为具有更高的可扩展性,基于架构
  2. 使用RESTful体系结构代替Web服务模型(SOA)
  3. 使用JSON代替XML进行数据传输(这样可以减少传输的字节数)
  4. 遵循Yahoo的性能准则
  5. 网络和硬件主题(例如负载平衡层体系结构)

2
您不能说PHP更快。在许多情况下,正确编写的ASP.NET应用程序可以胜过PHP。naspinski.net/post/AspNet-vs-php--speed-comparison.aspx
Andrew Lewis

+1实际上,您的“简单”解决方案将是UI-> Data Access-> Database。2 REST是“容易的”,因为大多数浏览器已经内置了它。无需重新创建命令响应API轮。3 JSON不仅更小,而且它不需要进行序列化-反序列化的步骤,因为您无需检查HTML实体。好东西。
Evan Plaice 2012年

1

有两种主要的扩展和扩展方法。

扩大规模是用一台功能更强大的机器代替一台机器。向外扩展意味着添加另一台计算机来完成现有计算机正在执行的工作。

任何高流量网站都需要具有扩展能力。需要完成的软件架构就是这样,以便在站点繁忙时可以轻松添加更多计算机。

通常,这意味着将应用程序分成多个层,以便每个层可以插入和播放更多服务器。

我会选择1,而不是直接进行服务。到目前为止,您只能扩展单片应用程序。


0

使用技术平台开发站点,该平台完全集成了对云的支持。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.