弹性伸缩原理
业务流量不是一条平滑的曲线,而是峰谷分明的波浪。大促高峰可能是日常的 10 倍甚至 100 倍。如果按照峰值准备资源,平时就是巨大的浪费;如果按照平时准备资源,大促就会崩溃。弹性伸缩,就是让系统「能屈能伸」的技术。
基于指标的扩缩容
弹性伸缩的核心是「根据指标自动调整实例数量」。常见的触发指标有三类:资源利用率、请求特征、业务指标。
资源利用率指标
CPU 利用率:最常用的扩容指标。当 CPU 利用率超过阈值(如 70%),说明计算资源紧张,需要扩容;当利用率持续低于阈值(如 30%),说明资源过剩,可以缩容。
内存利用率:适合内存密集型应用。但内存不像 CPU 那样能快速释放,扩容决策需要更谨慎。
磁盘 I/O:适合 I/O 密集型应用,如日志处理、数据导入导出。
请求特征指标
每秒请求数(QPS):直接反映负载水平。缺点是需要预估每实例的 QPS 上限,这个值在不同业务场景下差异巨大。
请求等待队列长度:比 QPS 更敏感。当队列开始积压时,说明处理能力已经不足,比 CPU 利用率更早发出预警。
连接数:数据库连接池、HTTP 连接数等。连接数接近上限时必须扩容。
业务指标
订单量:电商大促场景,订单量是最真实的负载指标。但这个指标通常需要业务系统提供,延迟较高。
活跃用户数:游戏、社交场景。活跃用户数突增时,需要预留更多资源。
消息队列积压量:消息队列的积压量直接反映下游消费能力。积压超过阈值时扩容消费者。
冷却时间与震荡问题
弹性伸缩看似简单,但实际使用中最大的坑是「震荡」——系统不断在扩容和缩容之间来回切换,像一个不稳定的天平。
冷却时间
冷却时间(Cooldown Period)是防止震荡的关键配置。扩容后,即使指标回落,也需要等待冷却时间结束才开始缩容;缩容后,即使指标上升,也需要等待冷却时间结束才开始扩容。
震荡的根因
震荡通常由以下原因导致:
指标选取不当:使用 CPU 作为扩容指标,但业务特点是「请求来了 CPU 飙升,处理完立刻下降」。扩容需要时间(30-60 秒),等实例启动好,CPU 已经降下来了,于是开始缩容。周而复始。
阈值设置不合理:扩容阈值太低(如 50%),导致频繁扩容;缩容阈值太低(如 20%),导致频繁缩容。
实例启动时间过长:实例启动需要 2-3 分钟,这段时间内指标已经回落,缩容决策会撤销刚完成的扩容。
解决方案
使用更平滑的指标:不用瞬时值,改用一段时间内的平均值。Kubernetes HPA 支持 targetAverageValue 或 targetAverageUtilization。
合理设置阈值和窗口:扩容阈值和缩容阈值之间保持足够距离(如 50% 扩容、20% 缩容),给系统留出缓冲空间。
设置扩容上限和冷却时间:防止单次扩容幅度过大,设置 scaleUp.policies 限制扩容速率。
预热机制:对于已知的流量高峰(如大促),提前手动扩容,而不是等待指标触发。
容量规划与弹性上限
弹性伸缩不是万能的,它有一个「弹性上限」。这个上限由两部分构成:系统容量上限和业务约束。
系统容量上限
物理资源上限:云环境下是账户配额,私有环境是机器数量。HPA 的 maxReplicas 应该设置在这个上限之内。
依赖系统上限:应用实例扩容了,但数据库连接池只有 100 个。如果每个实例需要 10 个连接,10 个实例就满了。扩容再多也没用。
带宽上限:公网带宽、负载均衡器吞吐量、消息队列消费能力,都可能成为瓶颈。
业务约束
冷启动延迟:Serverless 环境下,冷启动可能需要几秒钟。对于延迟敏感的业务,这个代价太高。
数据一致性:扩容意味着更多实例处理请求。如果涉及分布式事务,更多的参与者意味着更高的冲突概率和更长的等待时间。
成本约束:弹性伸缩是为了省钱,不是为了烧钱。如果业务量稳定,固定容量的成本可能更低。
容量规划建议
建立容量模型:基于业务指标(DAU、转化率、峰值 QPS)和系统指标(CPU、内存、I/O)的关联关系,建立容量规划模型。这个模型能回答「DAU 100 万时需要多少实例」。
设置弹性边界:在容量模型的基础上,设置合理的 minReplicas 和 maxReplicas。最小副本数保证基础可用性,最大副本数防止失控扩容。
保留应急储备:预留 20-30% 的余量应对突发流量。不等到资源耗尽才扩容。
Kubernetes HPA/VPA 实战
Kubernetes 提供了两种自动扩缩容机制:HPA(Horizontal Pod Autoscaler)和 VPA(Vertical Pod Autoscaler)。
HPA 详解
HPA 是最常用的弹性伸缩机制,通过调整 Pod 副本数来应对负载变化。
基础配置:
基于多指标的配置:
VPA 详解
VPA 通过调整 Pod 的资源请求(requests)来优化调度,适合内存或 CPU 需求随时间变化的场景。
HPA vs VPA
实际生产中,HPA 使用更广泛,VPA 通常用于辅助调优或特定场景。
CronHPA:定时扩缩容
对于可预测的流量波动(如每天的早高峰、每周的大促),可以使用 CronHPA 实现定时扩缩容。
常见误区
误区一:弹性伸缩能解决所有性能问题
弹性伸缩只能解决「容量不足」的问题。如果性能问题是代码 Bug、数据库慢查询、架构设计缺陷导致的,扩容只会让问题更快暴露。
误区二:minReplicas 设置为 1
单副本意味着单点故障。任何一次滚动更新或节点故障都会导致服务不可用。生产环境建议 minReplicas >= 2。
误区三:maxReplicas 设置过大
maxReplicas 不仅是容量上限,也是成本上限和风险上限。如果配置错误(如内存泄漏),自动扩容可能耗尽整个集群资源。
误区四:忽视缩容的影响
缩容时,正在处理的请求会被中断。如果使用的是无状态服务,负载均衡器会把请求路由到其他实例;如果是有状态服务,需要先处理完正在执行的请求。
延伸思考
弹性伸缩的核心价值不是「省钱」,而是「用合适的资源应对变化的负载」。省钱的副作用是,在流量低谷期释放资源;在流量高峰期获取资源。但实现这个目标,需要对业务有足够的理解——知道什么时候会涨、涨多少、涨多久。
盲目依赖自动弹性伸缩,可能导致成本不可预测、扩缩容震荡、甚至在关键时刻扩容不及时。更健康的做法是:先用容量模型预估基线,用 CronHPA 处理可预测的波动,用 HPA 处理意外情况。三者结合,才能真正做到「能屈能伸」。