业务流量从来不是一条平稳的直线。白天高、凌晨低,工作日高、周末低,大促当天可能是平时的十倍。如果按峰值买机器,平时就大量闲置;如果按均值买机器,高峰来了服务就扛不住。弹性伸缩(Auto Scaling)就是为解决这个矛盾而生的:让计算资源随负载自动增减,忙时扩容、闲时缩容。
这篇文章讲清楚弹性伸缩的工作原理——它靠什么触发、有哪些策略、冷却时间为什么重要、怎么和负载均衡配合、为什么有状态应用很难伸缩,以及用它的成本和注意事项。看完你应该能自己设计一套合理的伸缩策略,而不是简单地"CPU 超过 70% 就加机器"。
一、弹性伸缩的基本组成
一套完整的弹性伸缩通常包含四个部分,理解它们的关系是理解原理的前提。
伸缩组(Scaling Group)是管理单元。你定义"这个组里最少几台、最多几台、期望几台",以及用哪个镜像、哪种规格、挂在哪个负载均衡后面。组内的实例是同质的,可以互相替换,这是弹性伸缩能工作的前提。
伸缩配置(Launch Configuration / Launch Template)描述"新实例长什么样":镜像 ID、实例规格、系统盘、安全组、登录密钥、初始化脚本。扩容时按这个模板创建实例,所以模板必须包含应用能自动启动的全部信息——这是最容易踩的坑,新实例起来了但应用没起来,扩容等于白扩。
伸缩策略(Scaling Policy)定义"什么时候扩、扩多少、什么时候缩、缩多少"。这是本文的重点。
监控与健康检查是触发器和质量保障。监控提供指标数据,健康检查负责把不健康的实例剔除并替换。
二、靠什么触发:监控指标是开关
弹性伸缩本质上是"指标驱动的反馈控制"。系统持续采集指标,和阈值比较,超过就执行动作。
常用的触发指标分几类:
- CPU 利用率:最常用,也最直观。适合计算密集型服务,但对 IO 密集型或阻塞型服务不敏感——CPU 不高但请求已经排队了,这时用 CPU 触发就会反应迟钝。
- 内存利用率:适合内存敏感的应用,但要注意有些语言运行时内存不归还,缩容时容易误判。
- 网络流量/带宽:适合以流量为核心的服务,如下载、视频。
- 请求数/QPS:最贴近业务感受的指标,适合 Web 服务。QPS 涨了说明真实压力来了,比 CPU 更直接。
- 队列长度/积压任务数:适合异步任务处理,如消息队列消费者。积压多了就加消费者实例。
- 自定义指标:从应用或 APM 上报,比如"平均响应时间""在线连接数",灵活性最高。
选择指标的原则是:它要能真实反映系统的瓶颈在哪。用错了指标,要么扩容不及时(业务受损),要么过度扩容(成本浪费)。生产环境常见做法是"主指标 + 辅指标"组合,比如 QPS 为主、CPU 为辅,避免单指标误判。
# 概念性示例:定义一条基于 CPU 的伸缩策略(不同平台命令不同,此处示意逻辑)
# 目标:组内 CPU 平均利用率维持在 50%
# 规则:>50% 持续 3 个周期则扩容 1 台;<30% 持续 5 个周期则缩容 1 台
# 实际使用时请查阅所用云平台或编排系统的具体接口
三、策略类型:定时、动态、预测
伸缩策略大体分三类,实际项目里往往组合使用。
定时伸缩(Scheduled Scaling)按预设时间点调整容量。比如"每天 9 点扩到 10 台、22 点缩到 3 台",或者"大促当天 8 点提前扩到 50 台"。它的优点是确定、无延迟,适合负载规律性极强的业务。缺点是应对不了突发——流量不按剧本走就失灵。
动态伸缩(Dynamic Scaling)基于实时指标自动调整,是弹性伸缩的核心。它又分几种模式:
- 目标追踪(Target Tracking):你只设一个目标值(如 CPU 50%),系统自动计算并维持。这是最省心的模式,推荐优先使用。
- 步进伸缩(Step Scaling):按指标偏离程度分级扩缩。比如 CPU 60%-70% 加 1 台,70%-85% 加 2 台,85% 以上加 4 台。适合需要"偏离越多、扩得越猛"的场景。
- 简单伸缩(Simple Scaling):超过阈值就执行一个固定动作,简单但不够平滑。
预测伸缩(Predictive Scaling)用历史数据做机器学习预测,提前在流量上涨前扩容。它能解决"扩容有延迟、来不及"的问题,但对突发无规律的流量效果有限,且需要足够的历史数据。
| 策略类型 | 触发依据 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 定时伸缩 | 时间表 | 确定、零延迟 | 无法应对突发 | 规律性强的业务 |
| 目标追踪 | 实时指标目标值 | 省心、自动平滑 | 需要合适的目标值 | 大多数 Web 服务 |
| 步进伸缩 | 指标偏离程度 | 分级响应、更激进 | 规则需调优 | 压力变化剧烈 |
| 预测伸缩 | 历史数据预测 | 提前扩容 | 依赖数据、突发无效 | 有稳定周期规律 |
四、冷却时间:防止"伸缩抖动"
冷却时间(Cooldown)是弹性伸缩里最容易被忽视、却极其重要的机制。
想象这样一个场景:流量上涨,系统扩容 2 台。但新实例启动、应用初始化、注册到负载均衡需要时间(可能几十秒到几分钟),这期间负载还没降下来。如果系统在这段时间内又看到高指标,就会继续扩容,结果流量高峰过去后,一下子多出一堆实例,然后又被缩容,来回震荡。这就是"伸缩抖动"(Throttling / Flapping),既浪费资源又影响稳定性。
冷却时间的作用就是:一次伸缩动作执行后,在指定时长内不再触发新的伸缩动作,给系统时间让新实例真正生效、指标稳定下来。经验值一般是新实例启动时间的 1.5 到 2 倍。
还有两个相关概念要区分:
- 扩容冷却通常比缩容冷却短。扩容慢不得,流量来了要尽快加;缩容要谨慎,缩太快可能刚缩完又来流量。
- 预热时间(Warm-up)指新实例启动到能正常服务的时间。有些平台支持"预热模式",让新实例逐步接入流量而非一次性全量,避免冷启动被压垮。
配置冷却时间的经验:先测量实例从创建到可服务的真实时间,冷却时间设置为它的 1.5-2 倍;扩容阈值和缩容阈值之间留足间隔(比如扩容 70%、缩容 30%),避免在临界点反复触发。
五、与负载均衡的配合
弹性伸缩几乎总是和负载均衡(Load Balancer)成对出现,两者配合才形成完整闭环。
工作流程是这样的:负载均衡把用户请求分发到伸缩组内所有健康实例;监控采集组内实例的聚合指标;策略判断是否伸缩;扩容时新实例自动注册到负载均衡开始接流量,缩容时实例先从负载均衡摘除、等待连接排空、再释放。
关键细节有几个:
- 健康检查是前提。负载均衡的健康检查要能准确判断实例是否可服务。检查方式(HTTP 状态码、TCP 端口、间隔、超时、不健康阈值)配得不对,会导致好实例被误摘或坏实例继续接流量。
- 缩容要优雅下线(Deregistration Delay / Connection Draining)。实例被摘除时,正在处理的请求要处理完,否则用户会看到连接中断。这个等待时间要配置合理,太短会中断请求,太长会拖慢缩容。
- 会话保持和弹性伸缩有冲突。如果开了会话保持(Sticky Session),用户的请求绑定到某台实例,缩容时这台实例被移除,用户会话就丢了。解决办法是把会话外置到 Redis 等共享存储,让实例真正无状态。
# 概念性示意:负载均衡健康检查与优雅下线相关参数
# 健康检查间隔:10s,超时:5s,不健康阈值:3 次,健康阈值:2 次
# 优雅下线等待:30s(等正在处理的请求结束再摘除)
# 具体参数名与配置方式随平台而异
六、有状态应用为什么难伸缩
弹性伸缩的隐含假设是"实例可互换、随时增删"。有状态应用破坏了这个假设,因此很难直接用弹性伸缩。
难点主要有三:
数据本地化。如果数据存在实例本地磁盘,移除实例就会丢数据,新实例也没有旧数据。数据库、缓存、文件存储都属于这类。
会话状态。用户登录态、购物车存在本地,实例被替换后状态丢失。
主从角色。数据库有主库从库之分,不能简单地"加两台"就扩容,扩容还涉及数据复制、分片再平衡,这是复杂的工程问题。
应对思路有几条:一是把状态外置,应用自身无状态(最推荐,如会话存 Redis、文件存对象存储);二是对有状态服务用专门的水平扩展机制(数据库分库分表、分片集群),而不是通用弹性伸缩;三是用"垂直伸缩 + 少量水平",数据库通常更适合升配而非加机器;四是把有状态服务放在伸缩组外,只有无状态的计算层参与弹性伸缩。
七、成本与注意事项
弹性伸缩不是"开了就省钱",用不好反而更贵。
成本上,弹性伸缩的价值在于"按需付费"——只在实际需要时付费。但如果策略配置不当,会出现几种浪费:阈值太低导致频繁扩容,资源长期过量;冷却时间太短导致抖动,实例反复创建销毁;缩容规则保守导致资源长期闲置;镜像臃肿、启动脚本慢导致新实例迟迟不能服务,扩容期间还得靠原有实例硬扛。
注意事项,整理成一份清单:
- 实例模板必须包含完整的应用启动流程,新实例起来即可服务,无需人工干预。
- 应用尽量无状态,状态外置到共享存储。
- 设置伸缩组的最大实例数上限,防止异常指标导致无限扩容烧钱。
- 设置告警,监控"伸缩组实例数""扩容失败次数",扩容失败往往意味着配额不足或镜像有问题。
- 关注账户级别的资源配额(如可用区实例数上限),配额不够会导致扩容失败。
- 结合成本工具定期检查闲置实例和过度配置。
| 环节 | 常见问题 | 应对 |
|---|---|---|
| 指标选择 | 用 CPU 衡量 IO 密集服务 | 改用 QPS/队列长度等真实瓶颈指标 |
| 冷却时间 | 太短导致抖动 | 设为实例启动时间的 1.5-2 倍 |
| 缩容 | 缩太快丢请求 | 配置优雅下线等待时间 |
| 会话 | 会话保持绑定实例 | 会话外置,实例无状态 |
| 成本 | 阈值过松长期过量 | 定期审视策略与利用率 |
常见问题
Q:弹性伸缩和自动扩容是一回事吗?
基本是同一概念的不同叫法。严格说弹性伸缩包含"扩"和"缩"两个方向,自动扩容侧重"扩"。真正的弹性是动态的,会扩也会缩。
Q:云服务器弹性伸缩需要重启业务吗?
扩缩容本身不重启存量实例,只是增加或移除实例。但新实例的创建和应用启动是自动的,如果启动脚本有问题,会出现"实例起来了但服务不可用"的情况,要在测试环境充分验证。
Q:CPU 一直不高但响应变慢,为什么弹性伸缩没触发?
因为 CPU 不是你这个场景的瓶颈。可能是 IO、网络、数据库连接数或下游服务拖慢,此时要用能反映真实瓶颈的指标(如响应时间、队列长度)来触发。选错指标是弹性伸缩失效的头号原因。
Q:弹性伸缩能应对秒杀这种瞬间流量吗?
单纯依赖指标触发来不及,因为流量是瞬间起来的,等指标采集、判断、实例启动完成,峰值早过了。正确做法是"定时伸缩提前扩容 + 目标追踪兜底 + 缓存和限流削峰",多管齐下。
Q:缩容会不会影响正在进行的请求?
会有影响,除非配置了优雅下线。实例被移除前应先从负载均衡摘除,等待正在处理的请求完成(连接排空),再释放。这个等待时间要合理设置。
总结
弹性伸缩的核心是"指标驱动的自动增减容量",理解它要抓住四件事:用什么指标触发、用什么策略调整、冷却时间防止抖动、和负载均衡形成闭环。
- 优先用目标追踪策略,指标要选真实瓶颈(Web 服务优先 QPS/响应时间,任务类用队列长度)。
- 冷却时间设为新实例启动时间的 1.5-2 倍,扩容冷却短、缩容冷却长,阈值之间留出间隔防止抖动。
- 与负载均衡配合时,健康检查要准确、缩容要优雅下线、会话必须外置。
- 有状态应用天生难伸缩,优先把状态外置让应用无状态;数据库类用分片或升配而非通用弹性伸缩。
- 弹性伸缩不等于省钱,设置最大实例数上限、监控扩容失败、定期审视策略,才能真正控制成本。
企业QQ咨询




