容量规划与评估实践

容量规划的本质就是在「没有足够硬件资源」和「花钱买了太多硬件资源」之间的一种权衡;在同时,容量规划也是一门玄学,因为没人能清楚未来会发生什么,所以通常来说是数据和直觉相结合的过程。

容量规划背景

在没有进行容量规划之前,尝试问自己如下三个问题。

问题1 谁需要进行容量规划?

致力于成长为国内一线互联网公司,并经常需要为流量激增而大规模扩容的公司。

问题2 什么时间进行容量规划

容量规划就是资源管理,当资源有限且具有一定成本时就需要进行容量规划。

问题3 为什么要进行容量规划?

现在互联网,不仅是软件之间的互动,更多的是人和软件之间的互动。主动权不掌握在软件运营者的手中,某个话题的出现都会导致用户激增,进而导致网站崩溃,为了防止网站崩溃,就要精准预测流量,为不可预知的流量做准备。

容量规划目标

在没有目标之前,不要进行容量规划,也没有办法进行容量规划。

一般目标如下:

  • 服务SLA,通常包括可用性和性能指标两个维度,要给出具体数字,99.9%可用还是99.99%可用,比如有些系统提供商承诺99%可用性,给人一种可用性很高的错觉,其实算下一年就要有5k多分钟处于不可用状态。

另外就是时延,对于延迟敏感高的系统,不要用平均数,要用中位数,比如:P99.99 保证 50ms 以内延迟。因为多数服务都存在长尾问题。

  • 软件架构,服务是否低耦合,是否可以横向扩展。多数公司做架构都停留于编程语言和通信协议层面,但这仅仅是最表面的一层。要想提升稳定性,更多的是隔离、限流、熔断、超时、负载均衡、链路追踪、监控,每一个拿出来都可以当一个专门的课题去研究。
  • 基础设施架构,是否支持自动扩缩容,具体包括水平扩容,垂直缩放。
  • 灾难恢复,多数据中心建设,这个之前有过介绍

容量规划方法和过程

  1. 收集最近半年或者一个季度 QPS 增长趋势,根据增长趋势预估接下来的增长倍数;
  2. 根据预估流量算出所需硬件数量;
  3. 计算处理能力,并添加限流;
  4. 不断收集指标、持续优化系统处理能力,并校正容量规划指标。

下面我会针对这四个步骤进行详细解释

1、指标收集

每个(重要的)系统都应该量化它的处理能力并且可视化当前状态(QPS、延迟、错误率),如果不能,那就让它变得可量化、可视化。

服务运行指标不可或缺,不仅仅容量规划,也是日常监控告警指标的一部分。

指标收集有诸多陷阱,就以常用的 Prometheus 为例,当计算QPS时,应该用irate把瞬时峰值计算出来,而不应该使用rate;即便使用irate,可能还会存在误差,一般 Prometheus 的采集指标是 15s,只对规定采样周期内的最后两个样本进行计算,而忽略前面所有样本。

Grafana只是一个指标观测工具,不能完全靠它去做容量评估,我们知道当你查询最近半小时的 QPS 时,分钟展示;但是你进行容量评估可能会查看连续多天的数据指标,这样的话单位就变成了天,如果里面有一个短暂的峰值,grafana并不会展示,那么峰值可能被忽略掉。

基于肉眼查看界面会存在误判,所以不要依赖界面化操作,而是实现自动化指标查询。Prometheus 本身就是个时序数据库,可以通过HTTP调用的方式以采集周期为单位把某段时间内最大数据指标收集出来。例如使用以下表达式查询请求表达式在30秒范围内以15秒为间隔计算PromQL表达式的结果。

代码语言:javascript
复制
$ curl 'http://localhost:9090/api/v1/query_range?query=http_requests_total{environment=~"staging|testing|development",method!="GET"}
&start=2015-07-01T20:10:30.781Z&end=2015-07-01T20:11:00.781Z&step=15s'
{
   "status" : "success",
   "data" : {
      "resultType" : "matrix",
      "result" : [
         {
            "metric" : {
               "__name__" : "up",
               "job" : "prometheus",
               "instance" : "localhost:9090"
            },
            "values" : [
               [ 1435781430.781, "1" ],
               [ 1435781445.781, "1" ],
               [ 1435781460.781, "1" ]
            ]
         },
         {
            "metric" : {
               "__name__" : "up",
               "job" : "node",
               "instance" : "localhost:9091"
            },
            "values" : [
               [ 1435781430.781, "0" ],
               [ 1435781445.781, "0" ],
               [ 1435781460.781, "1" ]
            ]
         }
      ]
   }
}

建议每2个小时存储一个最大值,然后把以天、月为单位画出走势图,根据走势图预测下个周期预测值。

2、计算所需资源

既然资源评估,那就需要计算自己需要的资源,CPU、内存、磁盘;其中内存和磁盘使用都会存在一个固定趋势,根据现有指标相对更容易的计算出来。

这里通常有两个原则:

  • 一是可以回收资源,比如CPU和内存,随着进程的消失而回收,这类资源通常需要预测一段时间的峰值使用
  • 持续增长的资源,比如硬盘,就需要查看存储的增长曲线,根据增长曲线预测未来多久需要进行硬件的采购和安装上架

量化你的QPS和延迟的关系,量化你的QPS和硬件(CPU、内存、磁盘、IO)的关系, 量化你的每个请求需要消耗的资源。

下面我以计算 CPU 为例,说明下如何进行计算资源的评估。

首先我们需要计算出每个请求消耗的 CPU 资源,计算公式如下:

每个请求 CPU% = 总的 CPU% 消耗/请求总数

承载 QPS 最大值 = 100% * CPU 数量/ 每个请求消耗CPU%

首先根据监控查看 QPS 对应的 CPU 消耗,建议使用线上数据,如果第一次上线,则使用基准压测数据。

假设上述qps占用32core

  1. 每个请求占用的CPU资源 = 32 * 40%/13400 = 0.09%
  2. 32core满载的情况下承载 QPS 最大值 = 3200/0.09 = 35,555
  3. 当然按照业界标准一般CPU占用率安全线 85%,那么 35,555 * 0.85 = 30221 qps
  4. 如果要满足 10w qps 需求,那么就需要 106core = 100000/30221 * 32

当然这是一种资源评估方法,并不能完全解决服务中存在的问题,比如说 JVM 在某个不确定的时间发生了 GC、存在 SQL 慢查询....这种偶尔故障导致的CPU消耗超过阈值,只能具体问题具体分析,比如:JVM 调优,尽可能少发生 FGC。添加监控告警指标,出现不符合正常逻辑指标升高,告警、人工处理等。

3、采购硬件

硬件资源是软件运行过程中不可忽略的成本,只有根据上述数据评估清楚,到底需要购买多少硬件,才应该开始硬件的采购和安装过程。

事项

内容

完成时间

确定需求

采购理由

征求供应商报价

订购设备

物理安装设备

操作系统和应用程序配置安装

测试

上线服务

这里的原则是尽可能采购同类型的机器,减少机器之间的差异性,简化故障维修;当机器不同零部件出现问题时可以同型号装配,提高硬件资源利用率;最后尽量不做做定制化设置,有利于后期的自动化。

容量规划问题讨论

  • 性能优化和容量规划区别与联系

在我工作过程中,经常有人把性能优化和容量规划混为一谈,认为他们两个可以直接划等号,其实并没有什么关系,性能优化只是其中一个过程,通过性能优化可以提高服务处理能力,降低资源消耗,但是容量规划还是需要按部就班的做。

  • 产品规划前期没有容量规划,导致后期没有资源

在很多开发团队中,产品和开发甚至运维人员都是相对比较独立的团队,这就导致产品人员不关心开发进度、开发不关心运维如何部署,这个没什么好的办法,只能改变企业文化,加强产品开发运维的一体化,这就现在工作中倡导的DevOps。

  • 如何最大自己的资源

使用操作系统虚拟化技术,比如现在的Kubernetes,能够轻松完成资源的调度和分配,从而实现峰谷互补。

总结

容量规划这种事不去做,一直都是个空白,只要迈开第一步,随着时间的推移,会逐渐认识到自己服务的处理能力,容量预测也会变得更加准确,服务稳定性也会在一定程度上得到保障。