云服务器如何实现弹性扩容?CPU、内存与存储升级策略

大促开始前十分钟,监控面板上 Web 层 CPU 冲到 90%,响应延迟直线上升。这时候你有两种选择:把现有机器变强(垂直扩容),或者多加几台机器分担(水平扩容)。前者操作简单但有物理上限,后者理论上无限但没有改造到位的应用根本扩不动。云服务器弹性扩容的核心不是"会不会点那个按钮",而是知道什么情况下该往哪个方向扩、以及扩容之后操作系统这一侧还需要做什么才能生效。本文给出 CPU/内存/存储三类资源的完整升级策略和配套命令。

一、先选方向:垂直扩容还是水平扩容

维度垂直扩容 Scale Up水平扩容 Scale Out
做法提升单实例规格(4C8G → 8C16G)增加实例数量(3 台 → 10 台)
是否需要改造应用基本不需要必须无状态化 + 负载均衡
是否停机多数云平台需要重启变更规格不停机,逐台替换/加入
上限受单实例最大规格限制基本无上限
高可用性单点,不具备天然具备冗余
适合场景数据库主库、中间件、无法拆分的单体应用Web/API、微服务、计算worker

判断标准很实用:如果单个请求的响应时间已经随并发上升而急剧恶化,说明单实例触及瓶颈,先垂直扩容;如果响应尚可但整体处理能力不够,优先水平扩容。另外凡是涉及数据写入一致性、本地状态、序列号生成的服务,水平扩容前必须先解决状态外置。

二、CPU 与内存扩容:变更规格与支持的状态

云 CPU/内存扩容本质上是变更实例规格(Instance Type / Flavor)。由于 vCPU 数量、NUMA 拓扑和内存布局要在实例启动时确定,绝大多数云平台变更规格需要停机(先关机 → 变更 → 开机),停机时间通常在几十秒到几分钟。少数支持热升级的实例会在控制台标明"无需重启",选型时如果业务对停机敏感,应优先确认这一项。

# 扩容前记录当前规格(作为回滚比对基线)
lscpu | egrep 'CPU\(s\)|Thread|Core|Socket|Model name|Hypervisor'
free -h
nproc
dmidecode -t memory | grep -i size | head

# 关机前建议做的检查
df -h
docker ps -a            # 确认有状态容器能否随系统启动
systemctl list-unit-files --state=enabled
last reboot | head -5

2.1 扩容后操作系统侧的热上线

部分虚拟化平台支持 CPU/内存热插(hot-plug),变更规格并开机后资源还未立刻可用,需要在 guest 内手动上线:

# 1. 检查内核是否识别到新资源
lscpu | grep -E '^CPU\(s\)|online'
nproc
free -h
cat /proc/cpuinfo | grep processor | wc -l

# 2. 热上线新 CPU(热插场景)
grep -l 0 /sys/devices/system/cpu/cpu*/online | wc -l   # 查看离线 CPU 数量
for c in /sys/devices/system/cpu/cpu[0-9]*; do
  echo online > "$c/online" 2>/dev/null
done
# 重新核数
nproc

# 3. 热上线新内存块
grep -l offline /sys/devices/system/memory/memory*/state | wc -l
for m in /sys/devices/system/memory/memory[0-9]*/state; do
  [ "$(cat $m)" = "offline" ] && echo online > "$m"
done
free -h

# 4. 让内核重新读取硬件信息
udevadm settle
partprobe

# 5. 确认 NUMA 拓扑(多路大规格实例必看)
numactl --hardware
lscpu | grep -A5 'NUMA'

如果确认 nproc 与购买的核心数不一致,多半是内核未支持热插或需要在 BIOS/virtio 层面开启;此时重启一次通常能解决。

三、存储扩容:唯一能在线完成的资源

与 CPU/内存不同,云盘扩容可以在线完成,不需要停机,这在三种资源里是最友好的。但"控制台把 100G 改成 200G"只是第一步,操作系统内必须再做分区扩展和文件系统扩展两步,否则 df -h 完全看不到变化——这是最常见的误解。

3.1 完整扩容步骤

# 第 1 步:控制台或 API 将云盘容量调大(此步在云平台完成)
# 假设 /dev/vdb 从 100G 扩到 200G

# 第 2 步:在实例内确认底层磁盘已识别到新容量
lsblk
fdisk -l /dev/vdb
# 若 fdisk 报 "GPT PMBR size mismatch",说明分区表未更新,执行 partprobe 后重试

# 第 3 步:重新读取分区表
partprobe /dev/vdb
blockdev --rereadpt /dev/vdb
udevadm settle

# 第 4 步 A:有分区场景 —— 扩展分区到磁盘末尾
# 推荐用 growpart(云镜像通常自带 cloud-utils-growpart)
growpart /dev/vdb 1
# 或用 parted 交互/非交互修复 GPT 备份表
parted /dev/vdb print fix
parted /dev/vdb resizepart 1 100%

# 第 5 步 A:扩展 ext4 文件系统
e2fsck -f /dev/vdb1          # 离线检查,可选但建议
resize2fs /dev/vdb1
resize2fs -d 16 /dev/vdb1    # 打印调试信息,排查卡住时用

# 第 5 步 B:扩展 XFS 文件系统(注意 XFS 只能增不能减)
xfs_growfs /mnt/data          # 参数是挂载点,不是设备名!新手常错

# 第 6 步:验证
df -hT
lsblk

# ---------- LVM 场景(更灵活,推荐)----------
pvresize /dev/vdb                # 扩展物理卷
pvdisplay /dev/vdb | grep -i 'size'
lvextend -l +100%FREE /dev/mapper/vgdata-lvdata
lvextend -r -l +100%FREE /dev/mapper/vgdata-lvdata   # -r 自动扩文件系统
# 或分步
xfs_growfs /mnt/data
# resize2fs /dev/mapper/vgdata-lvdata
df -hT

关键提醒:

  • xfs_growfs 后面跟的是挂载点(如 /mnt/data),resize2fs 后面跟的是设备名(如 /dev/vdb1),两者不能混。
  • XFS 不支持缩容,ext2/3/4 支持缩容但必须先 e2fsck -f 且必须离线卸载,风险高。
  • 云盘通常只允许扩大不允许缩小,扩容前先想清楚目标容量,一次性多买的空间很难释放。
  • 分区数为 MBR 分区时单盘上限 2TB,超过必须用 GPT(parted /dev/vdb mklabel gpt)。

3.2 多块盘做 LVM 提升 IOPS

很多云平台对单块云盘有 IOPS 上限,横向堆盘并用 LVM 条带化(striping)能有效提升吞吐。这是"存储扩容"的另一层含义。

# 创建物理卷并加入卷组
pvcreate /dev/vdb /dev/vdc /dev/vdd
vgcreate vgdata /dev/vdb /dev/vdc /dev/vdd
vgs

# 创建条带化逻辑卷(-i 条带数,-I 条带大小,单位 KB)
lvcreate -i 3 -I 64 -L 300G -n lvdata vgdata

# 格式化为 XFS(mkfs.xfs 建议指定 su/sw 与条带对齐)
mkfs.xfs -f -d su=64k,sw=3 /dev/vgdata/lvdata

# 挂载并写入 fstab
mkdir -p /mnt/data
mount /dev/vgdata/lvdata /mnt/data
echo '/dev/vgdata/lvdata /mnt/data xfs defaults,noatime 0 0' >> /etc/fstab

# 后续扩容:加新盘 → pvcreate → vgextend → lvextend -r
pvcreate /dev/vde
vgextend vgdata /dev/vde
lvextend -r -l +100%FREE /dev/vgdata/lvdata

# 实测条带化效果
fio -name=seq -ioengine=libaio -direct=1 -bs=1M -size=2G -rw=read \
    -numjobs=1 -iodepth=16 -runtime=60 -time_based -group_reporting

四、自动弹性伸缩:让扩容自己发生

人工在控制台点"升配"永远跟不上突发流量。生产环境应当配置弹性伸缩(Auto Scaling):定义一个启动模板,然后由策略自动增删实例。

策略类型触发方式适用场景
目标追踪(Target Tracking)维持某个指标在目标值附近(如 CPU 平均 60%)通用首选,配置最简单
步进策略(Step Scaling)按阈值区间分级扩容(70% 加 1 台,85% 加 3 台)流量骤增、需要快速响应
定时策略(Scheduled)按时间点执行(每天 9:00 扩到 20 台)业务有固定波峰
自定义指标队列长度、连接数、QPS 等业务指标CPU 不能真实反映负载时
# 伸缩组中实例必须能用同一份镜像自动初始化,常用 cloud-init 触发配置拉取
# /etc/cloud/cloud.cfg.d/自定义脚本 或 user-data
cat > /var/lib/cloud/scripts/per-boot/00-join-cluster.sh <<'EOF'
#!/bin/bash
set -e
# 拉取配置中心的最新配置并启动服务
curl -sS http://config.example.com/bootstrap.sh | bash
systemctl enable --now app-agent
EOF
chmod +x /var/lib/cloud/scripts/per-boot/00-join-cluster.sh

# 校验 cloud-init 是否正常执行
cloud-init status
cat /var/log/cloud-init-output.log | tail -30
cloud-init single --name scripts-per-boot

两个容易踩的参数:

  • 冷却时间(Cooldown):扩容动作执行后的静默期,通常设为 300 秒左右。设得太短会导致反复扩容(新实例还没起来、指标没降又继续加),太长则响应迟钝。
  • 缩容保护 / 优雅下线:缩容时会直接删除实例,必须先让 LB 摘流量、等待存量请求处理完(通常配置 connection draining 延迟 30-120 秒),否则会造成用户请求失败。

五、扩容前的容量评估与实施清单

判断阈值参考(基于实践的经验值,可按业务容忍度调整):

  • CPU:5 分钟平均值持续 > 70% 且伴随 Load Average 超过 CPU 核数,应扩容。
  • 内存:可用内存低于总量 15% 或 si/so 持续大于 0(说明开始 swap),必须扩容。vmstat 1 观察 si/so 列。
  • 磁盘:容量使用率 > 80% 就需要规划扩容,因为扩容本身需要执行时间;> 90% 已属高危。
  • 磁盘 IOPS:iostat -x 1 中 %util 持续 > 80% 且 await > 20ms,说明已到性能瓶颈。
  • 网络:sar -n DEV 1 中带宽接近实例上限(各规格有 PPS/带宽限制)。
# 一次性评估当前资源水位
echo '--- CPU ---'; uptime; top -bn1 | head -3
echo '--- MEM ---'; free -h; vmstat 1 5
echo '--- DISK ---'; df -hT; iostat -x 1 3
echo '--- NET ---'; sar -n DEV 1 3
echo '--- TOP PROC ---'; ps -eo pid,comm,%cpu,%mem,rss --sort=-%cpu | head -10

# 换算公式:预估目标规格
# 目标核数 ≈ 当前核数 × (当前 CPU 使用率 / 目标使用率)
# 例:4 核跑在 90%,目标 60% → 4 × (90/60) = 6 核,向上取规格 → 8 核
# 目标内存 ≈ 当前实际用量 × 1.5(留 30%-50% 余量给 page cache 与突发)
  1. 确认扩容方向:单点瓶颈还是整体算力不足,决定 Scale Up 或 Scale Out。
  2. 垂直扩容:关机 → 控制台变配 → 开机 → 校验 nproc 与 free -h,必要时手工上线 CPU/内存。
  3. 水平扩容:确认应用无状态(session 外置到 Redis、文件外置到对象存储、定时任务单点化)。
  4. 存储扩容:控制台扩盘 → lsblk 确认 → growpart 或 parted 扩分区 → resize2fs/xfs_growfs 扩文件系统 → df -hT 验证。
  5. 扩容前后各打一次快照,作为回滚点。
  6. 配置弹性伸缩策略:设好目标值、冷却时间与缩容保护。
  7. 压测验证:用 ab、wrk 或 stress 模拟峰值,确认伸缩策略会按预期触发。
  8. 复核连接数:水平扩容后注意数据库连接池不能超限(实例数 × 每实例连接数 ≤ 数据库最大连接数)。
  9. 核对授权:按 CPU 核数计费的商业软件扩核后可能需要重新授权。
  10. 扩容完成后更新 CMDB 与监控阈值,避免容量已变而告警线未调整。
# 简单的压力验证工具
stress --cpu 8 --timeout 60s           # 压满 8 个核
stress --vm 4 --vm-bytes 1G --timeout 60s
ab -n 10000 -c 200 http://127.0.0.1/   # HTTP 压测
wrk -t12 -c400 -d60s http://127.0.0.1/ 

小结

云服务器弹性扩容的能力分三层:CPU/内存靠变更规格(多数需短暂停机)、存储可以在线扩展但必须补做系统侧扩分区与扩文件系统两步、真正的自动弹性则依赖弹性伸缩组加上无状态改造。把这三层的适用场景和操作步骤分清楚,扩容就不再是一件临时救火的事,而是可以按监控指标自动执行的常规动作。

避坑建议:

  • 扩了云盘但 df 没变化,99% 是漏了 growpart 或文件系统扩展步骤。
  • xfs_growfs 传挂载点、resize2fs 传设备名,传反会直接报错。
  • XFS 不能缩容,云盘也多数不支持缩配置,规划时要留出余量而不是盲目加。
  • 变更规格前必须打快照,变配偶发失败时有回滚点。
  • 水平扩容先解决 session 与本地文件,否则加多少台都不会真正分担流量。
  • 注意数据库连接池总量,实例翻倍可能把数据库连接打满,反而拖垮全站。
  • 设置合理的冷却时间,过短会导致扩容抖动,过长会响应迟钝。
  • 按核授权的商业软件要确认 License,扩核后可能无法启动。
  • 扩容后同步更新监控告警阈值,否则新容量下告警线失去意义。

延伸阅读:扩容的底层是虚拟化资源分配,理解 CPU 与内存的超分机制,有助于判断拿到手的算力是否稳定可靠。