如何从单台服务器扩展一个可以服务百万级用户的Web站点

分类: 小鸟云折扣卷 发布时间:2019-03-23 03:12

你构建了一个很少的每天只有几百的访问量的网站的时候,请求和影响是非常迅速的,比如说在线商城也会很顺利的处理订单。

当访问量从千位到万位的逐渐增加的时候,每小时每一分每一秒都有用户访问,对企业来说,是一件极好的消息,但是对于你来说确实坏消息。

但是现在,他需要的是以下的规模:

能够同时服务更多的用户

不能够宕机,随时待命

服务全球用户

几年前是怎么扩展的呢?

垂直扩展:部署相同的服务在强大的计算机上

水平扩展:并发的服务程序

今天已经不再垂直扩展了,为什么呢?

计算机性能越强,就需要更多的money

垂直扩展的计算机性能是有上限的

多核CPU意味着即使是一台计算机也可以有效地并行,所以为什么不水平扩展呢

上面应该是服务最初的样子,看起来非常的简洁

单一的应用服务运行这你的业务逻辑,单一的数据库存储着数据信息

这种单计算机和单数据库的部署方案,并不能很好的满足高可用

水平扩展的第一步就是添加一个反向代理

它就像旅店中的前台接待,顾客也可以自己去到指定的房间

实际的情况是前台要确认宾客,是否被允许进入到既定的房间

而且这个房间实际是存在的

房间如果是关闭的,前台可以很友好的告知宾客,不会让宾客觉很尴尬

恰好,反向代理是这样的。

通常,这些请求将从我们的服务器发送到Internet。然而,这一次请求来自Internet,需要路由到我们的服务器,因此我们将其称为“反向代理”。

(不太理解,标记一下)

代理应该完成的任务:

健康检查确保服务是正常运行的,(宾客的房间可用)

路由转发一个正确的端点,(房间是真实存在的)

权限 确保用户是有权限访问服务的,(宾客是有权入住房间)

防火墙 用户只能访问被允许的网络 (宾客不能访问其他宾客的房间)

当然代理还有更多的功能…….

大多数反向代理还有一个功能,作为一个负载均衡器

一百个用户在一分钟之内同时访问您的在线商店付款。不幸的是,您的支付服务一分钟之内,只能够处理50笔的交易,怎么解决呢?

解决方案:

你可以运行两台服务,负载均衡可以在两台服务器中分发支付请求,用户小A,访问服务器一,用户小B访问服务器二,以此类推。

那么,500个用户想要同时支付呢?当然,你可以扩展10台支付服务器,让负载均衡器来分配支付请求,确保服务能够正常运行

数据库的数据量问题:

使用负载均衡服务器可以分发请求,但是有一个很严重的问题!虽然我们可以使用数十、数百甚至数千台服务器来处理我们的请求,但它们都存储和检索来自同一个数据库的数据。

我们能不能用同样的方法扩展数据库呢?不幸的是,不可以,问题出现在了一致性上。系统服务使用时需要确保数据是一致的。

不一致的数据会导致各种棘手的问题?

小A看中了一款口红准备送给小女友,悲催的是,订单服务出现了错误,订单付款执行多次,由于数据不一致性,从账户中多次扣款,回去告诉女友,反被女友嘲笑。

那么,如何保持数据库一致性呢?

我们能做的就是把数据库服务分成多个部分。

比如说3个数据库服务,数据库服务器A专门用来接受和存储数据,除了服务器A外的服务器对外提供检索的服务

这个步骤有时候被叫做主/从设置,读写副本。

假设服务器从数据库中读取的次数要多于写入的次数

这个解决方案的优点是,一致性得到了保证,因为数据只写入到一个实例,并且从该实例流向一个方向,即从写到读,缺点是只有一个数据库实例是可以写入数据的。

这对于中小型网络项目来说是可以的,但是如果你运行Facebook就不行了。

后序的第9章,会再次提到数据库扩展

直到现在,我们仍在使用一个服务器,去处理所有事情:处理付款、订单、库存、服务网站、管理用户帐户等等。

这并不一定是件坏事——单个服务器意味着更低的复杂性,因此对我们的开发人员来说也不那么麻烦。但随着规模的扩大,事情开始变得复杂和低效,单体应用的缺点:

服务器利用率高,一台服务器完成了需要的事情

随着服务的健壮,程序员在同一台服务器上工作,开发效率低

版本迭代时,如果协作开发,可能会造成业务A可以更新,但是业务B暂时还不能上线的问题

业界的解决方案:微服务

功能划分不同的服务,部署独立,相互连接

每一项服务都可以单独调整规模,使我们能够更好地适应需求

开发团队可以独立工作,每个团队负责自己的微服务生命周期(创建、部署、更新等)。

每个微服务使用自己的服务资源,像图中的Payment、Account、Order服务都是单独的微服务

微服务:目前使用较为广泛的有SpringCloud 分布式部署方案,单微服务 SpringBoot。

更有效的工作,就是不工作,总结缓存和CDN再合适不过了

Cache缓存:

我们的Web程序中,有大量的静态资源文件,如JavaScript脚本文件,Image图片文件,Css样式表等等。我们是用缓存,不再从底层服务器进行Request请求,先在缓存中查找静态资源文件,如果存在请求资源的缓存,不用再次麻烦底层服务器发送,直接从缓存中获取。

Cache还有一个老铁,叫做内容传输网络,简称CDN,即分布在世界各地的大量缓存。

从接近用户的存储提供给直接用户内容,而不是将数据请求发到很远的世界各地去获取资源。

(需要手动东查一下资料)

消息队列简述:

想象一下,你去游乐园玩的时候,排队买票的场景,排队的过程就像是一个队列,排在最前的人,总是先买到了票,然后轮到了队列里的下一个游客,消息队列也是如此。

实际开发场景:

同样的概念也适用于大型web应用程序。

每分钟都有数十万张图片上传到Instagram、Facebook,每一张都需要处理、调整大小、分析和标记——这是一个耗时的过程,但是不是让用户等到上传完成所有这些步骤。

接收图像的服务器只做三件事:

它存储未经处理的原始图像

询问用户是否确认上传

文件加注解

从这里开始,任何数量的其他服务器都会接收这张便条,每台服务器都完成它的一个任务,勾掉它,然后把它放回堆里——直到我们的待办事项列表完成。管理这堆笔记的系统称为“消息队列”。

使用这样的队列有很多优点:

1.它将任务和处理器解耦。有时需要处理大量图像,有时只需要处理少量图像。有时有很多处理器可用,有时只有几个。通过简单地将任务添加到待办事项列表中,而不是直接处理它们,我们可以确保系统保持响应性,不会丢失任何任务。

2.它允许我们根据需求扩大规模。启动更多的处理器需要时间——所以当很多用户试图上传图片时,已经太晚了。通过将任务添加到队列中,我们可以推迟提供额外的处理能力

消息队列的场景:

限时秒杀、订单支付系统等等

分片是一种并行化应用程序堆栈的技术,方法是将它们分成多个单元,每个单元负责一个特定的键或名称空间。

这到底意味着什么呢?

举个例子,FaceBook服务器对外提供服务,如果按照每个人的姓名开头首字母,将架构分解为26个迷你Facebook服务模块,姓名A开头的用户使用A服务器,姓名B开头的用户使用B服务器,以此类推….

分片切分:

切分不必基于字母,但可以基于任意数量的因素,例如位置、使用频率(高级用户被路由到好的硬件,啧啧啧…..)等等,根据需要,您可以用这种方式分割服务器、数据库等...

一个价格昂贵的负债均衡器能够处理的请求也是有限的

幸运的是,有一个世界性的、分散的、稳定得令人难以置信的层,甚至可以在流量到达负载平衡器之前用于负载平衡。最棒的是什么?这绝对是免费的。这一层是“域名系统”,简称DNS。

文中可能有出入的地方,可以联系博主,部分内容没有原文作者说的有些模棱两可,比如说CDN,分片和缓存,需要查询大量的资料,没有看起来这么简单。

原文链接:-webapps-for-newbs-and-non-techies/