4、弹性伸缩策略:水平扩展与垂直扩展、基于负载的自动伸缩、定时伸缩策略、伸缩冷却时间设置

弹性伸缩,说白了就是让系统能「自动长胖」或「自动减肥」。

我见过太多团队,一上来就买最高配的服务器,结果平时利用率不到10%。也见过一些团队,流量高峰来了系统直接崩掉,运维半夜爬起来手动加机器。这两种极端,都是因为没有做好弹性伸缩策略。

今天我们就来聊聊,怎么把这件事做得既省钱又靠谱。

4.1 水平扩展 vs 垂直扩展:先选对方向

先搞清楚两个基本概念。我个人习惯把它们叫做「加人」和「加饭」。

  • 水平扩展(Scale Out/In):增加或减少服务器的数量。比如从3台变成10台。
  • 垂直扩展(Scale Up/Down):给现有服务器升级或降级配置。比如从4核8G升级到16核32G。

你可能会问:哪个更好?嗯,这得看场景。

对比维度 水平扩展 垂直扩展
成本 按需购买,成本可控 升级到高配机器,单价贵
弹性速度 分钟级(启动新实例) 秒级(重启即可)
架构要求 需要无状态设计 对架构无特殊要求
上限 理论上无限 受限于物理机上限
适用场景 Web服务、API网关 数据库、有状态服务

我在项目中遇到过一家电商公司,他们一开始只做垂直扩展。双十一流量上来,直接把服务器从8核升到64核。结果呢?单台机器扛住了,但一台挂了整个系统就瘫了。后来我帮他们改成水平扩展,虽然架构改起来费了点劲,但稳定性提升了一大截。

我的建议:无状态服务优先用水平扩展,有状态服务(比如数据库)优先用垂直扩展。如果预算允许,数据库也可以做读写分离,实现「伪水平扩展」。

4.2 基于负载的自动伸缩:让系统自己决定

手动伸缩太累了。你想想看,半夜三点爬起来加机器,谁受得了?

所以我们要做自动伸缩。核心思路就一句话:设定阈值,让系统自己判断。

常见的触发指标有这些:

  • CPU使用率:超过80%就加机器,低于30%就减机器
  • 内存使用率:同上逻辑
  • 请求响应时间:如果P99延迟超过500ms,说明压力大了
  • 队列深度:消息队列积压太多,说明消费能力不够
  • 并发连接数:连接数超过某个值,就该扩容了

举个例子,在AWS上用Auto Scaling Group配置:

# 创建伸缩组
aws autoscaling create-auto-scaling-group \
    --auto-scaling-group-name my-web-asg \
    --launch-template LaunchTemplateName=web-template \
    --min-size 2 \
    --max-size 10 \
    --desired-capacity 2 \
    --vpc-zone-identifier subnet-xxx,subnet-yyy

# 创建扩容策略:CPU超过70%持续5分钟,就加1台
aws autoscaling put-scaling-policy \
    --auto-scaling-group-name my-web-asg \
    --policy-name cpu-scale-out \
    --scaling-adjustment 1 \
    --adjustment-type ChangeInCapacity \
    --cooldown 300

# 创建缩容策略:CPU低于30%持续10分钟,就减1台
aws autoscaling put-scaling-policy \
    --auto-scaling-group-name my-web-asg \
    --policy-name cpu-scale-in \
    --scaling-adjustment -1 \
    --adjustment-type ChangeInCapacity \
    --cooldown 600
注意:阈值设置不能太敏感。我曾经见过一个团队,把CPU阈值设成50%,结果系统频繁伸缩,每次刚加完机器负载就降下来了,刚缩完负载又上去了。这就是所谓的「抖动」现象。建议设置一个「稳定窗口」,比如持续5分钟超过阈值才触发。

4.3 定时伸缩策略:可预测的流量,别浪费钱

有些流量是可以预测的。比如:

  • 每天早上9点到10点,用户登录高峰
  • 每周一上午,报表系统压力大
  • 每月1号,账单生成任务
  • 每年双十一、618大促

对于这些场景,用定时伸缩比用负载伸缩更划算。为什么?因为负载伸缩有滞后性——等CPU飙上去再扩容,用户已经感受到卡顿了。

定时伸缩的配置很简单:

# 每天早上8:30提前扩容,应对9点高峰
aws autoscaling put-scheduled-update-group-action \
    --auto-scaling-group-name my-web-asg \
    --scheduled-action-name morning-scale-up \
    --start-time "2024-01-01T08:30:00Z" \
    --min-size 5 \
    --max-size 20 \
    --desired-capacity 10

# 中午12:00缩容,午休时间流量低
aws autoscaling put-scheduled-update-group-action \
    --auto-scaling-group-name my-web-asg \
    --scheduled-action-name noon-scale-down \
    --start-time "2024-01-01T12:00:00Z" \
    --min-size 2 \
    --max-size 10 \
    --desired-capacity 3

我个人习惯的做法是:定时伸缩做「粗调」,负载伸缩做「微调」。比如大促期间,先用定时伸缩把基础容量从2台提到10台,然后让负载伸缩在10~50台之间自动调整。这样既保证了响应速度,又不会浪费资源。

成本优化小技巧:定时伸缩可以和「竞价实例」结合使用。比如在定时扩容时,优先使用竞价实例(便宜70%~90%),如果竞价实例被回收,再用按需实例兜底。这样能省一大笔钱。

4.4 伸缩冷却时间:别让系统「抽风」

冷却时间(Cooldown),是弹性伸缩里最容易忽略但又最重要的参数。

什么叫冷却时间?就是一次伸缩动作完成后,要等一段时间才能进行下一次伸缩。目的是防止系统「抽风」——刚加完机器,负载还没稳定下来,又触发了一次扩容。

我踩过这个坑。有一次给一个客户做配置,冷却时间设成了60秒。结果流量波动大,系统在5分钟内伸缩了8次。每次加机器要3分钟,缩机器要2分钟,整个集群一直在「加-缩-加-缩」的循环里打转。最后不仅没解决问题,还多花了不少钱。

冷却时间怎么设?我一般参考这几个原则:

场景 扩容冷却时间 缩容冷却时间 说明
Web服务(轻量) 120秒 300秒 缩容要更保守,避免频繁缩容
计算密集型任务 300秒 600秒 任务启动慢,冷却时间要长
数据库/缓存 600秒 900秒 有状态服务,伸缩代价大
大促期间 60秒 900秒 扩容要快,缩容要慢
避坑指南:我曾经把缩容冷却时间设得太短,结果流量一波动,机器刚缩完又得加回来。后来我学乖了——缩容冷却时间至少是扩容的2倍。宁可多保留几台机器,也别频繁缩容。

4.5 综合策略:三种方式搭配使用

实际项目中,我不会只用一种策略。我的习惯是「三管齐下」:

  1. 定时伸缩做基础:根据历史流量规律,提前准备好基础容量
  2. 负载伸缩做补充:应对突发流量,在基础容量之上动态调整
  3. 冷却时间做保护:防止系统抖动,保证伸缩动作稳定

举个例子,一个典型的SaaS应用配置可能是这样的:

# 基础配置
MinSize: 2
MaxSize: 50

# 定时策略
08:00 -> DesiredCapacity: 5   # 上班前扩容
12:00 -> DesiredCapacity: 3   # 午休缩容
18:00 -> DesiredCapacity: 2   # 下班后缩容

# 负载策略
CPU > 70% 持续5分钟 -> +2台,冷却300秒
CPU < 30% 持续10分钟 -> -1台,冷却600秒
请求延迟 > 500ms 持续3分钟 -> +3台,冷却120秒

# 特殊日期(如月底)
每月最后一天 -> DesiredCapacity: 10,MaxSize: 100

这样配置下来,平时能省不少钱。我记得有个客户,原来固定跑20台机器,改成这套策略后,平时只跑3~5台,高峰期自动扩展到30台。一年下来,云成本降了60%多。

最后说一句:弹性伸缩不是「配完就完事」的。我建议每个月至少review一次伸缩日志,看看有没有频繁伸缩、有没有阈值不合理的地方。云成本优化,是个持续迭代的过程。