如果你学会构建可扩展的应用程序,你就可以改变你的职业生涯
我们正在进行的工作
第一步
负载曲线
当可扩展性与一致性发生冲突时
处理负载
负载指标和统计数据
总结
致谢和脚注
我们正在进行的工作
网络非常庞大,而且每分钟都在变得越来越大。
更多人,做更多事,使用更多设备,连接速度更快。
种种迹象表明,各类应用的负载压力只会越来越大:从小型到大型,从B2C到B2B。越来越多的公司需要能够兑现可扩展性承诺的团队。
如今,每100名开发者中可能只有极少数人真正热衷于构建可扩展的产品。你就能站在市场的顶端。
第一步
可扩展系统是指能够在高度变化且经常增加的负载水平下继续以可靠的方式运行的系统。
系统的可扩展性问题很少是单变量分析的问题。它通常至少涉及二维思维:负载指标和时间段。更多的时候,它是一个多维的庞然大物。
一些二维问题示例如下:
- 当 IOPS 1在一秒钟内从 1,000 增加到 10,000 时,数据库系统如何扩展?
- 当网站页面浏览请求在一分钟内从 200 个增加到 5,000 个时,加载时间会受到怎样的影响?
请耐心阅读下文来了解多维度的内容。
负载曲线
我们首先需要表达的是负载对于我们每个系统意味着什么。
对于网站来说,负载可以是每秒的在线访问量或页面浏览量。对于数据库来说,负载可以是并发查询、I/O 操作数或数据进出量。
如何描述负载还取决于系统架构和业务案例。这正是事情开始变得复杂的地方。
例如,在一个电商网站上,系统或许能够很好地扩展,支持1万人同时在包含上千种商品的目录中购物。但如果一大群人只购买一件商品,会发生什么情况呢?
也许某位受欢迎的社交影响者的非常正面的评价刚刚在社交网络上疯传。
我们不想成为解释为什么由于系统限制而错过热门时刻的人。
当可扩展性与一致性发生冲突时
以一个可扩展的数据库系统为例。它将采用某种多节点复制技术。可以将其想象成将产品描述、价格等数据复制到不同的服务器上,以处理大量的读取请求。
如果每台服务器能够处理 1,000 RPS(每秒请求数),而我们需要处理 10,000 RPS,那么我们至少需要 10 台这样的服务器。相同的数据将在所有服务器中复制。其中一台服务器将充当主服务器,接收更新或删除请求。一旦数据点被修改,主服务器将通知其他服务器进行更新。
这通常被称为主从复制系统2,在数据库设置中非常常见。
现在想想一致性的问题。你知道机票“超额预订”吗?这算是一个一致性问题。航空公司是有意识地这么做的。但我们不希望两个顾客订购同一件商品,因为商店无法同时满足这两个订单。
确认购买后,系统会减少库存商品数量。问题就来了:数据库可能能够同时处理数百种不同商品的减少。但如果数千种商品在很短的时间内尝试减少相同的数量,会发生什么情况?
这种情况是由于市场趋势和人类行为造成的。开发人员在考虑负载和可扩展性时必须考虑这些因素。
处理负载
我们越努力预测系统可能遇到的挑战性负载场景,系统在现实中的表现就会越好。
需要考虑的是:
- 负载概况和指标
- 负载变化的幅度和速度
- 需要哪些资源来应对这些变化而不损害性能或可靠性
考虑负载曲线
让我们更深入地了解电子商务示例。
假设购物车模块负责在确认购买之前检查商品的库存情况。一种简单的方法是读取数据库中存储的商品信息中可用的商品数量,并在确认库存情况后立即减少该数量。
这种策略在负载增加的情况下可能会导致瓶颈甚至崩溃,因为所有订单请求都会同时减少相同的值。为了确保一致性,不仅主节点,所有副本节点都必须同时更新。
更好的方法
一种解决方案是使用多主3复制。这种类型的系统提供了处理并发请求的逻辑。不过,实现起来通常并不容易。
一些数据库服务会提供开箱即用的多主服务器功能。AWS的无服务器DynamoDB服务就是一个例子。
使用这种类型的服务可以节省大量时间。我们无需再解决基础设施集群和底层复制问题,而是可以专注于解决当前用户特定问题的可扩展性问题。
另一种可能性是使用消息队列作为缓冲区,而不是让购物车直接冲向数据库。所有订购的商品都会被放入队列中。后台作业负责从队列中提取订单并进行处理(检查库存、减少库存等)。
一旦订单中的所有商品都处理完毕,另一个后台作业就可以确认客户的购买。
队列缓冲区将前后端系统与数据库解耦,并允许它们分别进行扩展。这使得应对可扩展性挑战变得更加容易。即使使用多主数据库,消息缓冲区通常也是一个值得考虑的架构模式。
如何分析负载以及如何应对可扩展性挑战,很大程度上取决于具体用例。这里没有放之四海而皆准的策略。
这正是你在软件职业生涯中脱颖而出的关键所在。对于许多公司(不仅是大型公司,尤其是需要快速发展的初创公司)来说,开发团队必须考虑可扩展性,预测挑战,并构建一个具有弹性且可扩展的系统。
学习如何扩展系统,就能改变你的职业生涯。本文末尾推荐了一本很棒的书,如果你想深入了解的话。这并非易事,而且你永远不会对这个主题研究得太多。
思考资源
资源可以扩展:
- 垂直(扩大):例如增加 CPU 功率或 RAM
- 水平(横向扩展):例如,向集群添加更多服务器
许多健康的架构会混合使用这两种方法。有时,拥有许多小型服务器比几台高端机器更便宜,尤其是在负载变化很大的情况下。大型机器可能会导致过度配置和闲置资源的浪费。
当负载缩小时,关闭几台空闲的小型机器比频繁地将系统从大型机器移动到小型机器要容易得多。
在其他情况下,大型机器可能比小型机器集群运行速度更快、更便宜。
这取决于具体情况,开发人员必须尝试不同的方法来找到一种既适合性能要求又适合项目预算的方法。
使用无服务器系统极大地简化了开发人员对系统负载处理的责任。这些服务抽象了诸如扩展或缩减等决策,并提供了开发团队可以信赖的 SLA。
如上所述,AWS DynamoDB是一项出色的数据库服务。它开箱即用地解决了底层可扩展性和可用性问题。
对于需要快速上市和快速迭代的中小型团队和项目来说,使用DynamoDB这样的服务可以带来巨大的竞争优势。它使我们能够摆脱无差异的基础设施问题,专注于当前业务案例的可扩展性挑战。
掌握这些类型的服务对于提升开发人员的可扩展性也大有裨益。查看此知识库,了解更多关于可扩展数据库、计算引擎等的知识。
负载指标和统计数据
指标需要某种聚合或统计表示。平均值(算术平均值)通常不是一种很好的指标表示方式,因为它可能会产生误导。它无法表明有多少用户体验到了这种级别的性能。实际上,可能根本没有用户体验到这种级别的性能。
考虑以下应用程序负载和用户群:
用户 | 响应时间 |
---|---|
一个 | 210毫秒 |
B | 250毫秒 |
碳 | 240毫秒 |
D | 20毫秒 |
平均响应时间为 180 毫秒。但没有用户体验到这样的响应时间。75% 的用户体验到的性能低于平均水平。算术平均值对异常值高度敏感,上图的分布就是这种情况。
这就是为什么百分位数更常用于表示系统性能的原因。它们也是服务级别目标 (SLO) 4和协议 (SLA) 5 的基础。
最常见的百分位数是第 95、第 99 和第 99.9(也称为 p95、p99 和 p999)。
p95 水平是一个阈值,至少 95% 的响应时间低于该阈值。在上面的例子中,我们的 p95 是 250 毫秒。由于我们只有少量的请求样本,因此所有百分位数的阈值都是相同的。如果我们要计算 p75,则该阈值为 240 毫秒,这意味着:四分之三(75%)的请求在 240 毫秒内得到处理。
总结
考虑系统负载并使其能够在不同的负载曲线下平稳扩展并非易事。正因如此,你应该在这方面做得更好。
网络上只有少数应用程序需要担心规模的时代已经一去不复返了。网络已经非常庞大,而且还在不断增长。
每天都有越来越多的人加入到这个行列。越来越多的设备涌现:笔记本电脑、智能手机、平板电脑、智能手表、智能眼镜、智能戒指……谁知道接下来它们还会把什么智能化呢?
物联网设备正在爆炸式增长。网络速度只会越来越快。
正如我在开头所说:所有迹象都表明,各类应用程序的负载压力只会越来越大。越来越多的公司将需要能够提供可扩展系统的团队。
您可以成为市场上少数排名前 1% 的供应商之一。
订阅我们的知识库,当我们发布类似内容时,您会收到通知。
致谢和脚注
本文深受Martin Kleppmann所著《设计数据密集型应用程序》一书的启发。如果你对这个主题感兴趣,强烈推荐你阅读。
- 封面图片由Katee Lue在Unsplash上提供
- 手持植物图片由Daniel Hjalmarsson在Unsplash上拍摄
- 带有弹性的手图片由NeONBRAND在Unsplash上发布
- 正在伸展身体的女人图片由Andrés Gómez在Unsplash上拍摄
- 指标仪表板图片由Luke Chesser在Unsplash上提供
- 公牛碰撞图片由Uriel Soberanes在Unsplash上拍摄
- 垂直与水平缩放图像(由AccionLabs提供)
- 消息队列缓冲区图像由Christopher Demicoli提供
- 无服务器架构图像由Ritchie Vink提供
文章来源:https://dev.to/dashbird/if-you-learn-to-build-scalable-applications-you-can-change-your-career-42le