非常简短的回答
关键是架构。方法就是分而治之。方法是放松。
更长一点的答案
建筑学
建筑物最重要的组成部分是它的架构。空间由墙壁和地板、窗户和天花板(即建筑本身的元素)塑造的方式。建筑师的目的不是设计墙壁。他将它们设计为实际工作的次要部分:设计由墙壁塑造的空间。我们建造建筑物不是为了有墙,我们建造它们是为了在里面有空间。
我们首先设计功能,这是我们想要从软件中获得的功能。然后我们详细介绍如何使它成为可能,即构建产品。我们使用的技术不是主要的东西,它们是墙壁,我们真正想要的是空间本身。
充分了解我们想要从我们正在构建的软件中得到什么后,工程就变得更加容易且几乎是自动化的过程。技术难题开始出现在易于理解的定义中,幸运的是,有明显的解决方案。
分而治之
良好架构的一个非常重要的衡量标准是它使解决方案的组件清晰定义。当我们可以分别看到大图的这些组成部分时,我们可以将工作分成单独的部分。然后我们可以构建单独的东西来一起工作。
放松
也许这个标题听起来像是我想给文字带来一些幽默;但不,请不要误会我的意思。如果你有一个好的架构,你可以放松,你的 Web 服务器、数据库服务器、工程师、客户、用户和世界其他地方也可以。如果不是这种情况,则意味着您应该重新开始构建您的架构。
嗯?
嘿,我到底在说什么?它有一些段落和三个标题,除了软件之外,我没有使用任何软件术语。这种抽象的喋喋不休是为那些整天无所事事,懒洋洋地四处走动,说话,说话,说话的人准备的……我们是软件人,我们没有时间做这些。嘿,我,哈桑,别说了……!
好的,我会试试的;但首先,让我们放松一下……然后我们可以看一些真实的例子。
例子
假设我们正在为专业人士和个人开发网络发布服务。每个客户都有自己的网站,在我们的系统上运行。这些网站可以是访问量很少的普通个人网站,或者如果我们的业务幸运的话,我们的其他一些客户可以是像纽约时报这样的大型出版物。
我们需要解决两种可扩展性问题:随着我们开始拥有越来越多的客户、运行越来越多的网站而扩展我们的业务和系统。与第二个相比,这是一个非常简单的问题,它正在扩展单个网站,因为它获得越来越多的访问者,越来越多的数据,越来越多的应用程序在这些数据上运行。
我们可以将“如何扩展”的问题改写为“如何划分”,以更清楚地看到解决方案。如果我们可以将某些东西分成小块,我们可以通过添加更多资源来做这些小块,横向增长。
我们将拥有可以处理这些数据的数据和应用程序。假设我们有一台数据库服务器和一台 Web 服务器,并尝试使其具有可扩展性。
考虑我们将为我们的服务运行的网络服务器;如果我们不在这些机器上保留数据,它们将变成通用的、平等的组件、数据后端的小客户端,将这些数据连接到世界其他地方。通过保持我们的网络服务器轻便、愚蠢、空旷,我们可以轻松地让其中的许多服务器处理越来越多的请求。
好吧,将 Web 服务器变成愚蠢的代理并不是最聪明的主意。我们需要做一些事情,运行应用程序。而且,因为在我们的架构中,Web 服务器是最容易繁殖的,所以我们希望在这些 Web 服务器上做尽可能多的事情。我们将在下面的“更智能的划分”标题下继续解决这个难题。在此之前,让我们看看我们目前有什么样的架构以及它的可扩展性。
我们使用负载均衡器使许多 Web 服务器并行运行,并使用 DNS(甚至在请求到达我们的系统之前)将许多网站分成多个负载均衡器。例如,a.com、b.com、c.com 到负载均衡器 1,a-very-big-website.com 到负载均衡器 2,... 每组一个负载均衡器、一组 Web 服务器和一个数据库服务器在我们的系统中创建了一个单独的宇宙。现在我们可以拥有数以百万计的网站,并通过无限制地添加更多这些独立的宇宙来扩展我们的系统。我们可以为营销部门提供的尽可能多的网站服务于尽可能多的客户。我们的第一个问题已经解决了。运行大型大型网站怎么样?
更智能地划分
当然,我们不能像处理单独的网站那样将单个网站划分为单独的宇宙;但这并不意味着我们不能分割任何东西。我们将继续分而治之。为此,我们需要仔细研究我们解决的问题。
什么是网站?网页,支持内容,如css
和js
文件,多媒体内容,如图像和视频文件,以及数据,大量数据。多亏了 CDN 和云计算系统提供的出色存储服务,静态文件不再是我们问题的重要组成部分......
我们真正做的是渲染网页。上面,我们认为我们的 Web 服务器是我们数据库后端的非常轻量级的通用接口。我们还没有解决如何在我们的宇宙中运行应用程序。现在是时候这样做了。
对我们系统的每个请求都将到达一个站点,并由为该站点运行的应用程序处理。我们的网络服务器要做的第一件事就是决定请求属于哪个站点。在我们的数据库服务器上,我们保留了一个将主机名与站点匹配的表。对于我们拥有的每个新客户网站,我们都会在此表中添加一个或多个域以匹配该站点。对于我们的网络服务器的每个请求,我们将查询数据库服务器并决定加载哪个站点。好的?
不,不好。太糟糕了。为什么?
大数字,小数字
我们的网站数量很少;但是请求数量很大。与其他类型的数据(如博客网站上的评论)相比,Universe 上的网站数量的变化频率要低得多。在已建立的 Universe 中,此表可能每天更新几次。整天为每个请求一次又一次地查询这样一个很小的(几千条记录,很小!)数据库并不聪明。明智的做法是将此表的副本保存在 Web 服务器上,并仅在更新时更新。我们如何知道站点列表何时更新?我们可以保留一个带有数字的行作为我们的表格版本号。随着每次更新,我们可以增加这个数字。或者我们可以保留上次更新的时间戳。Web 服务器可以检查数据库服务器中的这个数字,并将它与它们的本地内存版本进行比较。如果表较新,我们再次拉取数据,覆盖本地内存中的副本。这样,我们将把数千个查询减少到很小的数量。大数,小数……
在这一点上,我们在建筑物上使用的材料开始变得重要。哪种语言,什么样的平台和数据库系统等等。现在,它们很重要,因为它们可以使我们的架构更好或更差地工作。例如,对于表的更新,我们的数据库服务器可以有一种机制来通知 Web 服务器有关更新。这样一来,我们就更进一步,彻底去除了对域站点表的不必要查询。所以,如果我们选择的系统提供了这样的机制,这意味着这些系统是我们架构的不错选择。
当我们很好地了解我们想要从我们的软件中得到什么时,以一种智能的方式划分事物就会自动发生。扩展数据库服务器非常困难。因为我们需要数据在一起。通过增加 Web 服务器的数量,我们可以无限制地横向扩展;但对于数据库服务器,这不适用。数据库服务器必须保持对数据的访问,并且机器具有我们无法以有效方式扩展的限制。
每个数据库系统都提供了分片或无共享架构等扩展方式。有时您必须使用这些;但正如我在论坛、博客和其他人们分享经验的地方看到的那样,恕我直言,人们使用这些内容过于激进和错误。他们让他们的数据库变得越来越大,然后“嘿,是时候扩展了,让我们添加一些分片吧。” 所有这些应用程序中的 99% 都是盲目运行的。人们将他们的问题抛给软件,并期望它们能像魔术一样得到解决。不幸的是,他们很快意识到没有魔法。
我们应该通过观察我们的数字来避免盲目运行解决方案:大数字,小数字。此外,通过了解我们系统的内部工作原理并通过架构解决问题,而不是大量使用材料。
这是一个架构解决方案:Architected Solution (by Calatrava )。
以下是其他依赖于材料而不是良好架构的解决方案:[盲运行解决方案 1 ]、[盲运行解决方案 2 ]
自己判断差异。
我们如何扩展数据库服务器?我们可以重新考虑我们的数据,而不是盲目地在中间划分表格。我们可以将用户帐户信息与站点模板分开吗?当然,为什么不?我们可以为旧数据和新数据保留不同的数据库服务器吗?有点困难,特别是考虑到搜索设施;但为什么不呢?
明智地划分,而不是盲目地划分!我接受有些时候你不能再分割它了;但是来吧,我们中有多少人在为 Google 或 Facebook 工作?
-- 嘿,伙计,我们有一个非常大的数据集,当我们运行时......
——嘘。首先,返回并检查您的数据集。它真的必须是一个大数据集吗?
大多数时候,不,它没有。我们只是不想承认...
如何迁移
从头开始重建一切需要许多企业无法承受的时间。更好的方法是在不重写每个组件的情况下构建我们当前的系统;而是将它们分离并重新定义为组件。这主要是分析,然后是很少的变化。系统上的每个函数调用都可以很容易地成为一个分割点。我们可以将系统从这一点分割成两部分。
只需几个小时对当前系统进行愉快的观察,就会向您展示如何划分这些部分的许多想法。一旦你把它们分开,就很容易重新设计所有东西,然后一块一块地重新构建你的新系统。如果我有一栋楼,并且我需要在同一块土地上建造一座更大的楼,那么在不搬迁所有已经居住在那里的人的情况下建造新楼是一项非常困难的工作;但并非不可能。当涉及到软件而不是建筑物时,这要容易得多。所以?
放松
它是软件。它很软。您可以复制数据,对其进行测试,删除所有内容,再复制一百万次。一旦你的架构设计得很好,你的错误永远不会导致灾难性事件。把一张6人的餐桌变成60人的餐桌是非常困难的;但是软件就是……软件,我们可以很容易地做这样的事情。放松。
——上面的问题涉及到这样一个领域,仅仅用几段话是不可能涵盖的。基于问题的这一部分:“但是,我仍然对适合更广泛受众的更一般的注意事项和指针持开放态度。” 我试图以一般形式提及事物而不深入细节。尽管我试图给出一些我的原则实际应用的小例子,但我知道我在这篇短文中留下了许多未解决的问题。我感谢评论中的任何批评和问题。