本指南总结了扩展的基本原则,从一台服务器扩展到能够服务数百万用户的Web应用程序。它面向在技术领域工作的新手和非开发人员。因此,如果您刚刚部署了您的多云平台VPN设置,那么本文并不适合您。
话不多说,那就让我们开始吧!
场景再现
你刚刚完成了你的网站、在线商店、社交网络或其他任何你想做的事情,把它放到网上,一切都很顺利:每天有数百名访问者经过你的网站,请求得到快速响应,订单立即得到处理,一切都很顺利。
但随后可怕的事情发生了:你变得成功了!
越来越多的用户蜂拥而至,数以千计,数以万计,每小时、每分、每秒……对您的企业来说,好消息对您的基础设施来说是坏消息;因为现在,它需要扩展。这意味着它需要能够:
- 同时为更多客户提供服务
- 始终可用,且无停机时间
- 为全球用户提供服务
扩展的工作原理
几年前,这篇文章一开始会讨论“垂直”与“水平”缩放(也称为向上扩展与向外扩展)。简而言之,垂直扩展意味着在更强大的计算机上运行相同的东西,而水平扩展意味着并行运行多个进程。
如今,几乎没有人再进行垂直/水平扩展。原因很简单:
- 计算机越强大,其价格就会呈指数级增长
- 一台计算机只能达到这样的速度,这对垂直扩展的范围设置了硬性限制
- 多核CPU意味着即使是一台计算机也可以有效地并行-所以为什么不从一开始就并行呢?
好了,就是水平扩展了!但所需的步骤是什么呢?
1. 单台服务器+数据库
这可能就是您的服务器最初的样子。运行业务逻辑的单个应用程序服务器和存储长期数据的数据库。事情很简单,但这种设置满足更高要求的唯一方法是在更强大的计算机上运行-这不是很好。
2. 添加反向代理
为更大规模的体系结构做好准备的第一步是添加“反向代理”。可以把它想象成酒店的接待处。当然,你可以直接让客人去他们的房间。但实际上,你想要的是一个中介,检查客人是否被允许进入,她的所有文件是否整齐,并正在前往一个实际存在的房间的路上。如果一个房间关门了,你希望有人用友好的声音告诉客人,而不是让他们陷入困境。这正是反向代理所做的事情。一般来说,代理只是一个接收和转发请求的进程。通常,这些请求会从我们的服务器发送到互联网。然而,这一次,请求来自互联网,需要被路由到我们的服务器,所以我们称之为“反向代理”。
这样的代理可以完成多项任务:
- 健康检查 运行情况检查可确保我们的服务器能够持续运行
- 路由 路由将请求转发到正确的终端
- 身份验证 身份验证确保用户确实被允许访问服务器
- 防火墙 确保用户只能访问他们被允许使用的网络部分
- …还有更多
3. 引入负载均衡
大多数“反向代理”还有一个诀窍:它们还可以充当负载均衡器。负载均衡器是一个简单的概念:假设在给定的一分钟内,有100名用户准备在您的在线商店付款。不幸的是,您的支付服务器一次只能处理50笔付款。解决办法?您只需同时运行两个支付服务器即可。
负载均衡器现在的工作是在这两个服务器之间拆分传入的支付请求。用户1向左,用户2向右,用户3向左,以此类推。
如果有500名用户想要一次性付款,你会怎么做?确切地说,您可以扩展到10个支付服务器,并让负载均衡器在它们之间分配传入的请求。
4. 扩展您的数据库
使用负载均衡器允许我们在多个服务器之间分担负载。但你能发现问题所在吗?虽然我们可以利用数十、数百甚至数千台服务器来处理我们的请求,但它们都在同一个数据库中存储和检索数据。那么,我们就不能以同样的方式扩展数据库吗?不幸的是没有。这里的问题是一致性。我们系统的所有部分都需要就他们使用的数据一致
。不一致的数据导致了各种各样的问题-订单被多次执行,从一个持有100元的账户中扣除两笔90元的款项,等等问题。那么,我们如何在确保一致性的同时扩大我们的数据库?
我们能做的第一件事就是把它分成多个部分。一部分专门负责接收和存储数据,所有其他部分负责检索存储的数据。此解决方案有时称为主从分离或读写分离。我们的假设是,服务器从数据库读取数据的频率远远高于向数据库写入数据的频率。此解决方案的好处是保证了一致性,因为数据只写入单个实例,并从那里单向流动,从写到读。缺点是我们仍然只有一个数据库实例可供写入。对于中小型网络项目来说,这是可以的,但如果你运行淘宝或微博,那就不行了。
5.微服务
到目前为止,我们只与一台服务器打交道:处理支付、订单、库存、为网站提供服务、管理用户账户等。
这不一定是一件坏事,单台服务器意味着更低的复杂性,因此对我们的开发人员来说也不会那么头疼。但随着规模的扩大,事情开始变得复杂和低效:
- 我们的服务器的不同部分得到了不同程度的利用,对于每个用户登录,可能有几百个页面浏览量要处理,有几百个资产要提供服务,但所有这些都是由同一服务器完成的;
- 我们的开发团队随着我们的应用程序的发展而壮大,但随着更多的开发人员在同一服务器上工作,他们更有可能相互干扰;
- 只有一台服务器意味着每当我们想要在线使用新版本时,所有事情都必须完成并清理。每当一个团队想要快速发布更新,而另一个团队只完成了一半的工作时,这就会导致危险的相互依赖。
这些问题的解决方案是一种席卷开发世界的体系结构范例:微服务
。这个想法很简单,将您的服务器拆分成多个功能单元,并将它们部署为独立的、相互连接的微型服务器。
这有很多好处:
- 每项服务都可以单独扩展,使我们能够更好地根据需求进行调整
- 开发团队可以独立工作,每个团队负责自己的微服务生命周期(创建、部署、更新等)
- 每个微服务可以使用其自己的资源,例如其自己的数据库,从而进一步减少了4中所述的问题。)
6. 缓存和内容分发网络
还有什么比高效工作更好的呢?根本不用工作!我们的Web应用程序的很大一部分是由静态资源组成的(一些永远不会改变的内容,如图像、javascript和css文件、某些产品的预渲染登录页等)。与其在每次请求时重新计算或重新服务这些资源,我们可以使用“缓存”(一个小的存储),它只记住最后的结果并将其分发给每个感兴趣的人,而不会打扰底层服务器。
缓存的大兄弟被称为“内容分发网络”或简称CDN–一个分布在世界各地的巨大的缓存阵列。这使我们能够从离用户物理位置很近的供应商向用户提供内容,而不是每次都将数据传输到全球各地。
7. 消息队列
你去过游乐园吗?你是不是刚走到售票处买票?可能不会——很有可能你已经在排队等候了。政府机构、邮局和游乐园入口处都是一个很好的例子,这个概念被称为“随需添加的并行性”–是的,它们是并行的:多个售票亭同时售票——但似乎从来没有足够的数量来立即为每个人提供服务,结果,开始排起了长队。
同样的概念也适用于大型网络应用程序。每分钟都有数十万张图片上传到Instagram、Facebook和Co,每一张图片都需要进行处理、调整大小、分析和标记–这是一个耗时的过程。因此,与其让用户等待他们的上传完成所有这些步骤,还不如让他们等待。
接收图像的服务器只做三件事:
- 存储未经处理的原始图像
- 向用户确认上传
- 在一大堆东西中添加了一个虚拟的笔记,说明需要做什么
从这里开始,这个笔记被其他任意数量的服务器接收,每个服务器完成它的一个任务,勾选它,然后把笔记放回堆栈——直到我们的待办事项列表完成。管理这堆笔记的系统称为“消息队列”。
使用这样的队列有许多优点:
- 它解耦了任务和处理器。有时需要处理大量的图像,有时只需处理少量的图像。有时有很多处理器可用,有时只有几个。通过简单地将任务添加到待办事项中,而不是直接处理它们,我们可以确保系统保持响应,并且不会丢失任何任务。
- it allows us to scale on demand. Starting up more processors takes time - so by the time a lot of users tries to upload images, it’s already too late. By adding our tasks to a queue we can defer the need to provision additional capacities to process them
- 它使我们能够按需扩展。启动更多的处理器需要时间–所以当很多用户尝试上传图片时,已经太晚了。通过将我们的任务添加到队列中,我们可以推迟提供额外的能力来处理它们
如果我们遵循上面的所有步骤,我们的系统现在已经准备好服务于相当大的流量。但如果我们想做大–真的很大–我们能做什么呢?好吧,我们还有几个选择。
8. 分片,分片再分片
什么是分片?它是这样的:
分片是一种将应用程序的功能并行化的技术,方法是将应用程序功能划分为多个单元,每个单元负责特定的键或命名空间
那么这到底是什么意思呢?实际上很简单:需要为20亿用户提供Facebook个人资料吗?将你的体系结构分解成26个迷你Facebook,每个都为用户提供不同的字母表。亚伦·亚伯拉罕?你会被斯塔克·A·扎卡里亚斯·扎克伯格传球吗?堆栈Z它是…。
分片不一定是基于字母,但可以基于任何数量的因素,例如位置、使用频率(高级用户被引导到好的硬件)等等。根据您的需要,您可以通过这种方式共享服务器、数据库或堆栈的几乎任何方面。
9. Load-balancing 负载均衡
单个负载均衡器只能做到这一点–即使您开始购买一些功能非常强大(也非常昂贵)的硬件负载均衡器,它们可以处理的请求数量也是有硬性限制的。
幸运的是,有一个全球范围的、分散的和令人难以置信的稳定的层,可以在流量达到负载均衡器之前就用于负载平衡。最棒的是什么呢?这绝对是免费的。这一层是“域名系统”–或简称为“域名系统”。将“arcenty.com”等域名映射到“143.204.47.77”等IP的全球注册表。该注册表允许我们为每个域名指定多个IP,每个IP指向不同的负载均衡器。