大促开始前十分钟,监控面板上 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 与突发)
- 确认扩容方向:单点瓶颈还是整体算力不足,决定 Scale Up 或 Scale Out。
- 垂直扩容:关机 → 控制台变配 → 开机 → 校验
nproc与free -h,必要时手工上线 CPU/内存。 - 水平扩容:确认应用无状态(session 外置到 Redis、文件外置到对象存储、定时任务单点化)。
- 存储扩容:控制台扩盘 →
lsblk确认 →growpart或parted扩分区 →resize2fs/xfs_growfs扩文件系统 →df -hT验证。 - 扩容前后各打一次快照,作为回滚点。
- 配置弹性伸缩策略:设好目标值、冷却时间与缩容保护。
- 压测验证:用
ab、wrk或stress模拟峰值,确认伸缩策略会按预期触发。 - 复核连接数:水平扩容后注意数据库连接池不能超限(实例数 × 每实例连接数 ≤ 数据库最大连接数)。
- 核对授权:按 CPU 核数计费的商业软件扩核后可能需要重新授权。
- 扩容完成后更新 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 与内存的超分机制,有助于判断拿到手的算力是否稳定可靠。
企业QQ咨询




