9.7

View in English

9.7 容量规划与需求预测

概述与动机

每一个系统都有其上限。计算核心会耗尽、磁盘会写满、连接池会枯竭,而一个早餐时还空着的队列到了午餐时间就可能溢出。容量规划这门学科,就是要把计算、存储和网络的供给,与你所预期的需求相匹配,并留出足够的余量,使得一个正常的日子永远不会逼近上限,而糟糕的日子也能优雅降级,而不是彻底崩溃。需求预测是另一半:预测有多少负载即将到来、何时到来、为何到来,从而让供给赶在需求之前到位,而不是在事故发生之后才姗姗来迟。

本章位于两个相邻章节之间,并与二者互为补充。第 3.5 章把可扩展性作为一种架构属性来讨论:系统是如何被构建成能够增长的,通过无状态设计、分片和水平扩展来实现。第 9.1 章讨论站点可靠性工程(SRE),设定容量必须捍卫的可靠性目标。在本章中,你把架构视为既定条件,把目标视为固定不变,然后回答一个定量的问题:为了让系统在预测到的需求以及你没有预测到的突发流量下,都能满足其服务水平目标(SLO,即第 9.1 章所述的可靠性目标),你需要购买、预留并留存多少各类资源。自动扩缩容和性能工程(第 2.16 章)是你在这里会用到的工具,但它们并不能替代规划,把二者误当作规划本身,是一个常见且代价高昂的错误。

对于大型团队而言,容量不再是某个工程师维护的一张电子表格,而变成了众多服务共同依赖的一个共享模型。一个由成百上千个服务组成的平台,共享着有限的资源池:数据库连接、消息代理的吞吐量、云账户配额、网络出口带宽。如果没有人掌握全局,一个团队的增长可能会让另一个团队陷入资源饥饿。在企业场景中,容量方面的失误要么表现为闲置基础设施上浪费的数百万美元,要么表现为恰好在最关键的时刻发生的令人难堪的事故。在政府场景中,风险进一步加剧。一个报税截止日、一个福利登记窗口期,或者一场公共卫生登记活动,会把整个国家的需求集中在短短几个小时之内,这种负载是法律强制要求的,而不是可选的,而公众会记住一个在自己设定的截止日期前就崩溃的网站。容量规划正是你兑现这些承诺的方式。

关键原则

  • 按预测需求加上刻意预留的余量来规划容量;不要让系统在接近饱和的状态下运行。
  • 把容量规划、自动扩缩容和性能工程区分开来;三者解决的是不同的问题。
  • 依据趋势、季节性、已知事件和业务增长来预测,而不仅仅依据上周的数据。
  • 通过负载测试和基准测试来找出你真实的极限,而不是靠猜测,也不要等生产环境替你发现它们。
  • 把接近饱和状态下的延迟视为一道悬崖,而不是一道斜坡;利用率目标的存在,正是因为排队论。
  • 了解你的硬性瓶颈:连接池、配额和单点不会自动扩缩容。
  • 有意识地在成本和可靠性之间取得平衡,并按固定节奏评审容量,而不是等事故发生之后才评审。

建议

把容量规划、自动扩缩容和性能工程区分开来

这三门学科常常被混为一谈,而这种混淆会导致你买错了解决方案。容量规划是一个中长期问题:在数周、数季度乃至数年的时间跨度内,你总共必须配置、预留并预算多少资源。自动扩缩容则是短期的、自动化的资源调整,按分钟级别跟踪负载:它能让你在规划所配置的这个范围内腾挪,但它无法凭空变出你从未预留过的配额,无法预热一个冷启动的数据库,也无法扩展一个只以单实例运行的组件。性能工程(第 2.16 章)通过让每一个工作单元变得更廉价来改变问题的形态,从而让同样的硬件能够服务更多的需求。

这种区分是实用性的。当一个系统在负载下变慢时,自动扩缩容会增加实例,性能工程会让每个实例变得更快,而容量规划则决定你是否负担得起这些实例,以及下游数据库能否接受它们将要建立的连接。一个只依赖自动扩缩容的团队,会撞上一个它从未规划过的硬性上限;一个只依赖性能工程的团队,则会在优化代码的同时,被账户配额毫不留情地限制住。你需要这三者兼备,并且需要知道眼前这个问题究竟该由哪一个来解决。

依据趋势、季节性、事件和业务增长来预测需求

一个建立在上周平均值之上的预测,会错过所有真正值得关注的时刻。你的预测应当建立在四个不同的组成部分之上。趋势是背后的基本方向:需求是在增长、持平,还是萎缩,速度有多快?季节性是重复出现的模式:每天早上九点的高峰、周末的周期性低谷、节假日前的年度激增。事件驱动的峰值是一次性的集中爆发:一次产品发布、一场营销活动、一次电视曝光,或者一个政府申报截止日。业务驱动的增长,则是你自己的路线图所创造出的需求:一个新市场、一位大客户的上线、一项让每次会话请求量增长三倍的功能。

针对每一种情况使用恰当的技术。将历史负载的时间序列分解为趋势和季节性,能为稳定需求提供一个站得住脚的基线。事件无法从历史数据中外推,因为它们本身没有历史,它们只能来自与业务方的沟通、阅读路线图,以及向市场营销和产品团队询问他们即将推出什么。代价最惨重的容量失误,几乎总是那些工程团队从未听说过的事件。解决之道在于组织层面,而非统计层面:建立一个常设的沟通渠道,让产品、市场营销和运营部门能够提前足够长的时间宣布即将到来的峰值,以便为其配置容量。

设定利用率目标,并尊重排队论所划出的那道悬崖

为了省钱而把基础设施”热”运行在 90% 利用率的这种直觉冲动是一个陷阱,其原因就是排队论,第 11.3 章对此有深入探讨。当一项资源趋近于完全利用时,等待时间不会平缓、线性地上升,而是会急剧爆发。一台利用率为 50% 的服务器还有充裕的余量;同一台服务器在 90% 利用率下,延迟可能会恶化好几倍,而到了 95%,队列可能会彻底失控。接近饱和状态下的延迟是一道悬崖,而不是一道斜坡,用户会以超时、重试和错误的形式感受到这道悬崖,而这远远早于该资源在技术意义上被”用满”之前。

这正是为什么容量规划人员会把利用率目标设定得远低于 100%()对延迟敏感的服务通常设定在 50% 到 70% 的区间,而对能够容忍排队的、以吞吐量为导向的批处理工作,则可以设定得更高。这个目标不是浪费,而是可预测延迟所付出的代价。要从 SLO 出发来选定目标:如果你的延迟目标很严格,你的利用率上限就应当更低,因为排队所产生的尾部延迟,正是最容易击穿 SLO 的元凶。余量(headroom)和安全边际(safety margin)其实是同一个概念的两种表述。余量是正常负载与容量之间的差距;安全边际则是把这个差距表述为一种保险,用来应对预测值偏高、一次故障切换导致负载集中,或者一个你没能预见到的突发峰值。

通过负载测试和基准测试来找出真实的极限

你无法围绕一个你从未测量过的极限来做规划。负载测试会向系统施加合成或重放的流量,观察延迟、吞吐量和错误率随负载上升而如何变化,以及它们在何处崩溃。基准测试则孤立地测量单个组件,以确定其上限:每个实例每秒能处理多少请求、每个数据库节点每秒能处理多少写入、每个消息代理分区每秒能处理多少条消息。二者合在一起,能告诉你规划所需要的两个数字:一个单位容量能提供多少能力,以及整个系统会在哪里彻底崩溃。

要进行几种不同类型的测试。负载测试会逐步加压到预期峰值,确认 SLO 在留有余量的情况下依然能够保持。压力测试会突破崩溃点,观察系统是如何失败的,因为一个优雅降级的系统,与一个直接崩溃的系统截然不同。浸泡测试会在数小时或数天内维持中等负载,以暴露只有在长时间运行后才会出现的内存泄漏、连接耗尽和磁盘写满等问题。峰值测试会突然施加负载,检验自动扩缩容和缓冲机制能否在用户察觉之前将其吸收。要针对类似生产环境的数据和拓扑结构进行测试,因为在一个玩具数据集上测出来的极限是会撒谎的。当系统发生变化时,要重新运行这些测试,这样你手头的数字描述的才是你现在拥有的系统,而不是一年前的那个系统。

有意识地选择配置策略

云服务商允许你以在价格与灵活性之间进行权衡的不同方式购买同样的容量,而把这些方式恰当地混合搭配起来,正是真正省钱的地方。按需容量灵活但昂贵:你为随时启动和停止的能力支付全价,这适合不可预测、短期存在的负载。预留容量(一年或三年的承诺,或者节省计划)以承诺持续使用为条件,换取更低的单位价格,适合你稳定的基线负载。竞价实例以大幅折扣出售闲置容量,但可能在很少预警的情况下被收回,适合能够容忍中断的工作,例如批处理和无状态工作节点。

行之有效的模式是分层的。用预留容量覆盖你稳定的基线负载,以获得最低的单位成本;用按需自动扩缩容来吸收日常和每周的波动;把能够容忍中断的批处理工作推给竞价实例,以收获折扣。为那些无法容忍从零扩容所带来的冷启动延迟的服务,保留一个预先配置好的热缓冲池,这样突发峰值面对的是已经就绪的容量,而不是新实例启动过程中排起的队列。恰当的组合是一项投资组合决策,它会随着你的需求形态和服务商定价的变化而变化,因此需要不断重新审视。

梳理那些不会自动扩缩容的硬性瓶颈

自动扩缩容会滋生一种危险的自信,因为许多极限位于能够扩缩容的那个环节的下游,并不会随之移动。数据库连接池就是经典的例子:把你的无状态层从 10 个实例扩展到 100 个,每一个实例都会向同一个数据库开启连接,而该数据库对并发连接数有一个硬性上限,一旦达到就会开始拒绝新连接。云账户几乎对一切都设有配额:每个区域的实例数、IP 地址数、每秒 API 调用次数、函数并发数。架构中的任何一个单点()一个主数据库、一个领导者节点、一个共享缓存、一个受许可证限制的设备()都是一道其他地方的水平扩展无法抬高的上限。

要把这些明确列出来。维护一份书面清单,记录从一次请求到其响应之间的每一个硬性极限:连接池大小、配额数值、单实例组件、第三方速率限制、许可证席位数量。对于每一项,都要记录当前值、当前用量,以及触发该限制所需的负载水平。这份清单,正是一份能描述整个系统的容量计划,与一份只描述容易扩展的弹性部分、却让一个连接池悄悄终结你的发布的容量计划之间的区别所在。要提前提升配额,因为服务商批准配额提升可能需要数天时间。

为峰值事件而不仅仅为平均值做配置

平均值会掩盖真正重要的时刻。一个按平均负载配置规模的系统,会恰好在峰值时刻失败,而对许多组织而言,峰值恰恰是重点所在:一年中购物最集中那天的零售激增、一场直播决赛的流媒体峰值、报税截止日当天的税务门户,或者福利网站在登记开放时的流量。要针对这些具名的事件逐一进行规划。从业务方估算峰值(预期并发用户数、每次会话的请求数,以及相对于正常日的倍数),按该峰值留有余量地进行配置,在该水平上进行负载测试,并在事件发生之前就完成容量的部署,而不是在事件当中手忙脚乱。

要把发布或截止日当作一个配有操作手册的运营事件来对待。提前预热缓存和缓冲池,提前提升配额,在这段窗口期内冻结有风险的部署,并安排能够在预测偏低时采取行动的值班人员。事件结束后,要记录实际的峰值,以及你当时距离极限有多近,因为这个数字是明年计划最好的输入。政府的截止日尤其值得格外小心:它们是自我设定的、公开已知的,且无法更改,因此没有任何理由感到意外,出问题时也无处可藏。

对容量进行监测,并按固定节奏进行评审

容量规划依赖数据,而这些数据来自第 9.2 章所述的可观测性。追踪每一项受限资源(CPU、内存、磁盘、网络、连接池、队列深度)相对于其上限的利用率,这样你就能在余量消失之前看到它正在缩小。要直接关注饱和信号:队列长度、等待时间和拒绝率,都能揭示排队悬崖正在逼近。要在数周的时间跨度上追踪这些趋势,以推算按当前增长速度,某项资源何时会触及其上限,并针对这个推算结果设置告警,而不仅仅是针对当前值,这样你才能在撞墙之前而不是撞墙之时就完成配置。

要按月度或季度等固定节奏进行容量评审,而不仅仅是在事故发生之后。在每一次评审中,要将预测与实际需求进行比较并修正模型,逐一检查硬性极限清单并核对每一项的余量情况,查看即将到来的事件和业务计划,并决定要预留、提升或退役哪些资源。要维护一个活的容量模型:一份简单的文档或电子表格,将需求驱动因素映射到资源需求上,这样任何人都可以问”如果流量翻倍,数据库会怎样”,并从这个模型中得到答案,而不是从一次事故中得到答案。这个模型永远不会完美,但一个书面的、定期修正的模型,永远胜过直觉。

权衡:优点与缺点

方法优点缺点
高利用率目标单位成本更低;闲置容量更少接近饱和时延迟会爆炸式增长;没有余量应对峰值或故障切换
充裕的余量延迟可预测;能吸收峰值和故障切换稳态成本更高;可能掩盖低效
预留容量稳定基线负载下单位价格最低需求下降或转移时存在承诺风险
按需容量灵活;能按分钟级别匹配可变负载单位价格最高;可能让预算措手不及
竞价实例为可中断工作提供大幅折扣可能不经通知就被收回;不适合有状态或延迟攸关的工作
自动扩缩容在规划所划定的范围内自动跟踪负载无法超出预留配额;存在冷启动;会掩盖下游极限
缓冲池(热容量)能瞬间吸收突发峰值需要为峰值之间的闲置容量付费

核心的张力在于成本与可靠性之间,而没有哪一种设置能够同时优化二者。精打细算地运行能省钱,直到某一天一次峰值撞上一个已经饱和的资源,延迟随即跌下排队悬崖。宽裕地运行能让你睡得安稳,但要为大部分时间都闲置着的余量付费。要用 SLO、而不是恐惧或吝啬来化解这种张力。配置足够的余量,以在预测峰值加上一定边际的情况下满足可靠性目标,仅此而已,然后让FinOps(云支出的财务运营,第 9.4 章)去搜寻那些无助于捍卫任何 SLO 的浪费。目标是有意识的平衡:每一美元刻意购买的余量,都要换来一份已知量的可靠性;每一美元被有意识地削减的浪费,都是因为它换不来任何东西。

与团队讨论的问题

  1. 我们是否真的知道各个硬性瓶颈会在什么负载水平下触发,还是我们在假设自动扩缩容会拯救我们? 大多数团队能告诉你他们的实例会自动扩缩容,但大多数团队却说不出他们主数据库的并发连接上限、他们最重要的第三方服务的 API 速率限制,或者限制其函数并发数的账户配额。正是这些极限会终结一次发布,而它们并不会随着无状态层的扩容而移动。如果有的话,带上那份书面的硬性极限清单来讨论;如果没有,这一缺失本身就是一个发现。对于每一项极限,你需要三个数字:上限、今天的用量,以及二者相遇的那个需求水平。任何一处你说不出这三个数字的地方,就是一个你正在凭一厢情愿来管理的瓶颈。

  2. 我们上一次以类似生产环境的数据,把负载测试打到即将到来的最坏峰值水平,是什么时候,SLO 是否留有余量地保持住了? 一份容量计划,是一组关于系统在负载下将如何表现的断言,而一个未经测试的断言,只是一个穿着西装的猜测。真正重要的峰值不是上个月的平均值,而是下一次发布、假期或截止日,而这个测试只有在数据和拓扑结构接近生产环境时才有意义,因为在一个玩具数据集上测出来的极限是会撒谎的。带上你们最近一次压力测试和浸泡测试的结果,包括系统在何处崩溃、以及崩溃时是如何失败的。如果诚实的答案是你们从未有意把系统推到过它的崩溃点,那么你们将会在生产环境中、在最糟糕的时刻、在用户的注视下,发现那个崩溃点。

  3. 产品、市场营销和运营部门如何在一次峰值发生之前告知工程团队,提前多久告知? 代价最惨重的容量失误,往往不是建模上的错误,而是工程团队直到流量涌入才第一次听说的事件。预测可以从历史数据中外推趋势和季节性,但事件本身没有历史,因此只能来自策划这次事件的人。带上最近三次需求峰值来讨论,对每一次都问一问工程团队获得了多少天的预警,以及这是否足以预留容量并进行负载测试。你想要看到的证据,是一个具备足够提前量的常设沟通渠道,因为光是云配额的提升就可能需要数天时间。如果这个渠道不存在,那么你们的容量计划恰恰对它本应保护的那些时刻视而不见。

  4. 每一个对延迟敏感的服务实际运行在什么利用率目标之下,我们能否把这个数字追溯到其 SLO,而不是追溯到某个成本目标? 这一点很重要,因为把基础设施”热”运行的压力是持续存在的,而且往往来自组织中那些只看到账单、却看不到排队悬崖的部门,因此除非这个目标被明确写下来、并从延迟目标出发加以论证,否则它会不断向上漂移,直到某一次峰值撞上边界。相互竞争的考量一边是实实在在的金钱,另一边是尾部延迟,而诚实的立场是:低于 100% 的余量是可预测延迟所付出的代价,而不是应当被削减的浪费。带上你们排名靠前几项服务当前的利用率、每一项所捍卫的 SLO,以及你们在该利用率下负载测试所测得的延迟,这样讨论才能建立在证据、而不是直觉之上。在一个由共享资源池支撑众多服务的企业或政府平台上,要统一约定这个目标,并记录谁有权更改它,因为单个团队悄悄提高自己的上限,可能会把其他人所依赖的资源推下悬崖,让所有人都受损。

  5. 我们预留容量、按需容量和竞价容量的组合比例是多少,我们上一次重新审视它是什么时候,它是否依然匹配我们需求的形态? 这个组合比例,正是最大的持续性节约和最大的持续性浪费共同藏身之处,因为一个以按需价格支付的稳定基线负载,每一个小时都在烧钱,而一个过度承诺的预留仓位,则要为一个需求已经超出或跌破的容量付费。这里的张力在于成本与灵活性及承诺风险之间:预留容量单位成本最低,但会把你锁定住;竞价容量更便宜,但可能不经通知就被收回;按需容量则以溢价换取自由。带上目前按成本划分的比例、它本应覆盖的需求曲线,以及任何竞价工作负载的回收率和影响范围,这样与会者才能判断这些可中断的工作是否真的可以被中断。在企业和政府场景中,要把预留承诺与采购和预算周期挂钩,因为多年期的承诺和节省计划是财务义务,财务和审计部门会要求这些承诺依据预测需求、而不是上个季度的便利来加以论证。

  6. 当一个具名的峰值事件即将到来时,谁负责预热、配额提升、部署冻结和”放行/不放行”的决定,这是否被写成了一份我们演练过的操作手册? 峰值事件正是容量规划存在的意义所在,而它们最常见的失败原因,往往不是计划本身出错,而是当天在压力之下,没有人对执行这份计划负责。这里相互竞争的考量是速度和自主性同协调之间的矛盾:团队想要继续发布,然而在激增窗口期内一次有风险的部署,可能会把数月的配置工作毁于一旦,因此必须有人握有冻结和叫停发布的权限。带上你们下一次重大事件的操作手册、配额提升和缓冲池预热所需的提前量,以及上一次各个角色分别由谁担任、交接是否顺利的记录。对于一个自我设定、公开已知、且无法更改的政府截止日,要明确指定负责人和上报路径,因为你没有削减负载或让公民改天再来的选项,而一个无人负责的峰值,在真正到来时也不会有人去捍卫它。

行业视角

初创企业。 你最稀缺的资源是工程注意力,因此要让容量规划保持精简,并依靠云服务商的弹性来应对日常波动。你唯一不能省略的,是一份书面清单,列出那些不会自动扩缩容的硬性极限:你主数据库的连接上限、你最重要的第三方服务的速率限制,以及在突发功能或媒体曝光下你会触及的账户配额。在你们第一次真正的流量激增之前,要在生产规模大小的数据上,把负载测试打到正常峰值的数倍,因为自动扩缩容给你的那种脆弱的自信,恰恰会在数据库拒绝连接的那一刻被打破。

小型企业。 你们没有容量专家,预算也紧张,因此应把这当作一个”购买并配置”的问题,而不是一个建模项目。优先选择能替你吸收扩容工作的托管服务,设置支出告警和简单的利用率仪表盘,这样失控的账单或趋于饱和的资源才能被及早发现,并了解那几个决定你们全年走势的具名事件(季节性抢购、某个大客户上线)。为你们稳定的基线负载预留容量以削减账单,并抵制住在需求形态几乎不变的情况下,去构建一套你们维护不起的预测系统的冲动。

企业。 这里的问题是数百个服务背后共享的、有限的资源池,因此容量就变成了投资组合治理:一份持续维护的硬性极限清单、由 SLO 集中推导出的利用率目标,以及一个根据实时定价不断重新审视的、预留容量、按需容量和竞价容量的有意组合。要标准化负载测试、压力测试、浸泡测试和峰值测试,让每个团队都以相同的方式在类似生产环境的数据上进行测量,并按固定节奏运行容量评审,赶在事故之前发现正在缩小的余量。要为这种协调明确预留预算,因为当没有人掌握全局模型时,一个团队的增长可能会让另一个团队陷入资源饥饿。

政府。 需求往往被法律要求集中在一个无法更改的、公开已知的截止日,因此要专门针对这个具名的峰值进行规划,并配置宽裕的安全边际,因为你没有削减负载或让公民改天再来的选项。采购规则塑造着容量的配置方式:多年期的预留承诺和供应商配额协议,必须依据预测需求来论证,并且要经得起审计,因此要保持预测、负载测试证据和硬性极限清单都有据可查、经得起推敲。在可能的地方公开发布合理的预期,提前很久就向服务商提升相关限制,并在每个周期记录真实的峰值,因为公共问责意味着一个在自己设定的截止日前崩溃的门户网站,是全国上下都能看到的失败。

示例

初创企业。 一家十人规模的初创公司在自动扩缩容的云基础设施上运行一款消费者应用,因为实例数量会随负载增长而感到安心。他们第一次登上电视曝光,一小时内流量涨了三倍,无状态层的扩容表现完美,然而应用还是崩溃了:每一个新实例都向数据库开启了连接,直到数据库触及连接上限,开始拒绝新连接。这次教训重塑了他们的实践方式。他们在数据库前面加了一个连接池管理器,把从一次请求到一次响应之间的每一个硬性极限都记录下来,并在一个生产规模大小的数据集上,把负载测试打到正常峰值的数倍。他们用一份预留容量承诺来覆盖稳定的基线负载以获得折扣,并保留一个小型的热缓冲池,让下一次突发峰值面对的是已经就绪的容量。这些改动花费了一周时间,把他们那种脆弱的自信,转化成了一份他们能够站得住脚地捍卫的计划。

企业。 一家全球零售商把自己一年中最大的销售日,当作全年最重要的容量事件来对待。提前数月,一个跨职能团队根据往年的趋势和季节性,加上商品规划,构建出一份需求预测,通过一个容量模型将其转化为资源需求,并按预测峰值留有充裕余量地进行配置。他们在类似生产环境的数据上,对整条路径进行负载测试、压力测试、浸泡测试和峰值测试,提前数周提升每一项相关的云配额,预热缓存和缓冲池,并在这段窗口期前后冻结有风险的部署。预留容量以较低成本覆盖稳定基线负载,按需自动扩缩容吸收日常曲线波动,而可中断的批处理工作则运行在竞价实例上。在活动期间,可观测性系统会实时追踪每一项受限资源相对于其上限的状态,并针对预计的饱和情况、而不仅仅是当前值发出告警。这一天平静地过去了,而这正是这番规划所换来的结果。

政府。 一家国家税务机构运营着一个申报门户网站,其需求被法律要求集中在一个无法更改的截止日前的几天,那时全国上下同时提交申报。该机构专门针对这一峰值进行规划,而不是针对一个毫无意义的年度平均值。它根据往年数据和人口数据估算并发申报人数,按该峰值配置宽裕的安全边际()因为没有削减负载或让公民改天再来的选项()并在现实的数据上,针对预计的并发量进行负载测试。团队维护一份书面清单,记录每一个配额和单点故障,提前很久就向服务商提升各项限制,并把利用率目标设定得足够低,让排队悬崖始终远离截止日的激增。每个申报季结束后,他们都会记录真实的峰值,以及当时还剩下多少余量,为明年的模型提供输入。公众看到的是一个在它被设计要应对的那一天依然正常运行的门户网站,而这正是这个机构承诺的全部意义所在。

商业理由:动机、投资回报率与总拥有成本

容量规划的回报体现为两项方向相反的、被避免的成本,而这正是这门学科的价值所在。配置不足的代价是事故,而峰值事件期间的事故代价最为高昂:恰好在受众最多的时刻,损失营收、损失交易、损害声誉。一个在其最大销售日宕机的零售网站,或者一个在报税截止日崩溃的政府门户网站,会在一个糟糕的小时之内,赔上数年规划工作的全部收益。配置过度则以相反的方式付出代价:闲置容量的云账单,而在企业规模下,整个基础设施舰队中长期存在的几个百分点的过度配置,一年就可能累积到数百万美元。容量规划正是那门找到刻意中间地带的实践:足以在峰值期间捍卫 SLO,仅此而已,不多不少。

采用这门学科的成本,主要在于纪律,而不是工具。你需要构建一份需求预测、把硬性极限记录下来、按固定节奏运行负载测试、混合搭配你的配置策略,并定期举行容量评审。总拥有成本(TCO)会从两个方向同时改善:更少的容量驱动型事故,降低了停机和应急响应的成本;而持续的资源调优,加上一个合理的预留与竞价组合,则降低了稳态的基础设施账单。要向领导层证明其合理性,就把容量与他们已经在关注的数字联系起来。把配置不足与峰值停机每小时损失的营收、以及带有合同罚金的 SLO 违约联系起来,把配置过度与第 9.4 章所述的 FinOps 浪费报告联系起来。这个论证不是抽象的审慎之谈,而是一个你可以有意识地设定的刻度盘两端,都实实在在关系到金钱。

反模式与陷阱

  • 把自动扩缩容当作计划: 信任弹性实例,而一个数据库连接池、账户配额或单点,却在悄悄限制着整个系统。
  • 为省钱而”热”运行: 把目标定在 90% 以上的利用率,一头撞上排队悬崖,延迟随即爆炸式增长,SLO 随之被击穿。
  • 用平均值代替峰值: 按平均负载配置规模,让系统恰好在那个证明其建设合理性的峰值事件上失败。
  • 仅依据历史来预测: 外推趋势和季节性,却错过了工程团队从未被告知的发布或活动。
  • 未经测试的极限: 围绕一个无人测量过的崩溃点做规划,然后在最糟糕的时刻,在生产环境中发现它。
  • 玩具数据的负载测试: 在不现实的数据和拓扑结构上测量容量,得出的数字对真实系统撒了谎。
  • 没有硬性极限清单: 凭记忆和一厢情愿来管理配额、连接池和单点,而不是依靠一份书面、持续维护的清单。
  • 要么全部预留、要么完全不预留: 过度承诺预留容量,而需求后来超出或跌破了它,又或者为一个稳定基线负载全额支付按需价格。
  • 只在事故之后才进行容量评审: 把规划当作被动的救火,而不是一个提前于需求进行配置的固定节奏。

成熟度模型

  • 第 1 级,启动: 容量是被动、临时应对的。团队在资源耗尽之后才去添加,完全信赖自动扩缩容能解决一切,没有预测、没有硬性极限清单,也没有负载测试。峰值事件全凭运气应对,发布和截止日期间的事故被当作坏运气来看待。
  • 第 2 级,发展: 基本的实践开始出现,但因团队而异。一些监控能显示利用率,一些负载测试会在大型活动前进行,主要的配额已被了解,某些地方存在一份粗略的预测,但该模型没有被持续维护,下游的瓶颈常常被忽略,余量的设定依靠经验法则,而不是依据 SLO。
  • 第 3 级,标准化: 容量规划是一门文档化、在全组织范围内强制执行的学科。需求预测综合了趋势、季节性、事件和业务增长;一份书面的硬性极限清单被持续维护;利用率目标由 SLO 推导而来;负载测试、压力测试、浸泡测试和峰值测试按固定节奏针对类似生产环境的数据运行;配置策略有意识地混合了预留、按需和竞价容量。一个常设渠道将事件预警从产品和市场营销部门传递给工程团队。
  • 第 4 级,管理: 容量依据基准被衡量和控制。每个周期都会把预测与实际需求进行比较,并追踪、压缩误差;利用率、饱和信号,以及相对于每一项硬性极限的余量,都被趋势化并针对预测值、而不仅仅是当前值设置告警;峰值事件结束后会对照真实观测到的峰值进行复盘;配置组合比例、预留承诺覆盖率和每单位 SLO 的成本,都作为指标被报告,并用于门禁放行或不放行的决策。决定预留、提升或退役什么资源的是数据,而不是直觉。
  • 第 5 级,协同: 容量规划在整个组织范围内被持续改进并加以集成。预测被自动验证和优化,饱和情况在到来之前就被推算并针对性地配置,配置组合根据实时定价不断优化,峰值事件依据演练过的操作手册运行,成本和可靠性在整个平台范围内有意识地依据 SLO 加以平衡。容量模型是一项共享的、自适应的资产,会随着需求形态和服务商定价的变化而重新平衡整个资源舰队。

讨论思路

  1. 你们目前对延迟敏感服务的利用率目标是多少?你能否从 SLO 和排队行为、而不是从省钱的愿望出发来论证这个目标?
  2. 你们哪些组件完全无法自动扩缩容?当其中一个达到饱和时,系统的其余部分会发生什么?
  3. 如果下个季度你们的流量翻倍,哪项资源会最先触及上限?你需要多少天的提前量才能把它提升上去?
  4. 你们如何决定预留容量、按需容量和竞价容量的组合比例?你上一次依据实际需求形态重新审视它是什么时候?
  5. 当一个峰值事件即将到来时,谁负责预热、配额提升和”放行/不放行”的决定?这是否被写成了一份操作手册?
  6. 你们的容量告警是提前数周针对预计的饱和情况发出的,还是仅仅在墙已经近在眼前时,才针对当前利用率发出?

关键要点

  • 容量规划把供给与预测需求加上刻意预留的余量相匹配;这有别于自动扩缩容(短期的、在既定范围内的调整)和性能工程(让单位工作变得更廉价)。
  • 依据趋势、季节性、已知事件和业务增长来预测,并从产品和市场营销部门获取事件预警,因为事件没有历史可供外推。
  • 尊重排队论所划出的悬崖(第 11.3 章):接近饱和时延迟会爆炸式增长,因此要依据你的 SLO 设定利用率目标,并保留真正的余量。
  • 通过在类似生产环境的数据上进行负载测试、压力测试、浸泡测试和峰值测试来找出极限,并维护一份书面清单,记录那些不会自动扩缩容的硬性瓶颈。
  • 用热缓冲池混合搭配预留容量、按需容量和竞价容量,逐一规划具名的峰值事件,并按固定节奏评审容量,而不是等事故发生之后。

参考资料与延伸阅读

  • Betsy Beyer, Chris Jones, Jennifer Petoff, and Niall Richard Murphy (eds.), Site Reliability Engineering: How Google Runs Production Systems
  • Betsy Beyer, Niall Richard Murphy, David K. Rensin, Kent Kawahara, and Stephen Thorne (eds.), The Site Reliability Workbook: Practical Ways to Implement SRE
  • John Allspaw, The Art of Capacity Planning: Scaling Web Resources in the Cloud
  • Neil J. Gunther, Guerrilla Capacity Planning: A Tactical Approach to Planning for Highly Scalable Applications and Services
  • Martin L. Abbott and Michael T. Fisher, The Art of Scalability: Scalable Web Architecture, Processes, and Organizations for the Modern Enterprise
  • Brendan Gregg, Systems Performance: Enterprise and the Cloud
  • Leonard Kleinrock, Queueing Systems, Volume 1: Theory
  • J. R. Storment and Mike Fuller, Cloud FinOps: Collaborative, Real-Time Cloud Financial Management