技术指南
VPS 架构验收:识别虚拟化、资源边界与运行兼容性
从客体可见证据核对 CPU 架构、虚拟化信号、cgroup 配额、资源压力与应用兼容,并保留无法证明的未知项。
虚拟化标签只说明实现线索,套餐数字只说明商家承诺;真正能决定应用是否可运行的,是客体架构、有效资源边界、持续压力、存储身份和发布物平台是否同时满足需求。验收应保存这些层的独立证据,并明确哪些事实无法从实例内部证明。
来源解释 VPS 基础,本文收敛为架构验收
归档来源完整讨论 VPS、KVM/OpenVZ、x86/ARM、配置、线路和运维。本文保留虚拟化类型需要核对、CPU 架构影响依赖、规格必须实测和第三方脚本先审阅;不沿用 KVM 必选、容器必差、资源天然独享、固定内存/带宽/IO 门槛、线路等级排名、单次跑分判定超售或特定产品推荐。
先把套餐标签改写成可验收契约
| 声明 | 实例内可核对 | 仍需外部证据 |
|---|---|---|
| CPU 架构与数量 | `lscpu -J`、`uname -m`、有效 cgroup CPU 配额 | 宿主型号真实性、持续可用份额与调度策略 |
| 内存 | 客体可见内存、`memory.max`、`memory.events` | 宿主超分、回收策略和长期邻居影响 |
| 虚拟化 | VM/容器信号与最内层环境 | 物理拓扑、隔离强度、管理面限制与 SLA |
| 存储 | 挂载源、文件系统、容量与实际工作负载延迟 | 底层介质、缓存层、冗余与故障域 |
| 应用兼容 | 二进制/镜像平台、内核能力、启动与健康检查 | 未来版本、闭源授权和外部服务兼容 |
完整虚拟机、共享内核容器和托管服务不是质量等级
| 交付模型 | 通常可见的边界 | 决策问题 |
|---|---|---|
| 完整虚拟机 | 独立客体内核与虚拟设备 | 是否需要自选内核、特定模块、Windows 或嵌套能力 |
| 共享内核容器 | 独立用户空间但共享宿主内核 | 所需 capability、模块、cgroup、设备和网络操作是否开放 |
| 托管应用/数据库 | 平台抽象运行时和部分运维 | 备份、扩缩、权限、导出和退出路径是否满足业务 |
| 物理服务器 | 独占硬件控制面 | 硬件、网络、备件和故障恢复是否有团队承担 |
模型选择来自能力约束,而不是一个名称的声望。能在受限容器内完整通过验收的应用,没有必要为未使用的内核控制付费;需要自定义内核或设备的工作负载,也不能靠容器中的 root 名称获得这些能力。
先做不安装软件的客体证据包
stamp=$(date --utc +%Y%m%dT%H%M%SZ)
out="$HOME/vps-architecture-$stamp"
umask 077
install -d -m 0700 "$out"
uname -m >"$out/uname-machine.txt"
getconf LONG_BIT >"$out/word-size.txt"
lscpu -J >"$out/lscpu.json"
(systemd-detect-virt || true) >"$out/virtualization.txt"
(systemd-detect-virt --vm || true) >"$out/virtualization-vm.txt"
(systemd-detect-virt --container || true) >"$out/virtualization-container.txt"
findmnt --json --target / >"$out/root-mount.json"util-linux 的 `lscpu` 从 sysfs、`/proc/cpuinfo` 和架构库收集信息,并明确说明虚拟环境中看到的通常是客体配置,不是物理宿主。脚本应使用 JSON 或显式列;默认的人类可读布局可能变化,物理 socket/core 拓扑在虚拟硬件上也可能不准确。
把虚拟化检测当能力线索,不当信任证明
systemd 当前文档说明检测器可区分完整虚拟机和容器;嵌套时默认只报告最内层环境,`--vm` 才可在容器内继续检查外层机器虚拟化。返回 `none` 也不证明物理机身份,更不证明没有未识别或被隐藏的虚拟化。
同时核对客体架构和实际发布物
| 层 | 示例名称 | 容易混淆的点 |
|---|---|---|
| Linux 客体 | `x86_64`、`aarch64` | 内核报告的运行架构 |
| 发行版包 | `amd64`、`arm64` | 命名词汇可能与 `uname` 不同 |
| ELF 二进制 | ELF64 / Machine | 闭源程序还可能要求特定指令或动态库 |
| 容器镜像 | `linux/amd64`、`linux/arm64` | 多平台索引选择匹配变体;仿真不等于原生性能 |
uname -m
getconf LONG_BIT
lscpu -J | jq '.lscpu[] | select(.field == "Architecture:" or .field == "CPU(s):")'
readelf -h /path/to/application | sed -n '/Class:/p;/Machine:/p'
file /path/to/applicationDocker 当前文档说明容器共享宿主内核,运行代码必须兼容宿主架构;多平台镜像可以为不同 OS/架构提供独立 manifest,仿真则可能显著慢于原生执行。验收应在目标实例启动真实候选并走健康路径,而不是只检查 manifest 中出现目标字符串。
读取当前进程的有效 cgroup,而不是只看全机数字
cg_rel=$(awk -F: '$1 == "0" { print $3 }' /proc/self/cgroup)
case "$cg_rel" in /*) ;; *) exit 1 ;; esac
case "$cg_rel" in *'..'*) exit 1 ;; esac
cg_dir="/sys/fs/cgroup$cg_rel"
printf 'cpu.max: '; cat "$cg_dir/cpu.max"
printf 'memory.max: '; cat "$cg_dir/memory.max"
printf 'memory.current: '; cat "$cg_dir/memory.current"
sed -n '1,12p' "$cg_dir/cpu.stat"
sed -n '1,12p' "$cg_dir/memory.events"| 接口 | 当前语义 | 验收方式 |
|---|---|---|
| `cpu.max` | 每个 period 可用的最大 CPU 时间;`max` 表示该层不设上限 | quota/period 换算有效上限,并检查祖先层与实际节流 |
| `cpu.stat` | 用量以及可用时的 period、throttled 计数 | 记录区间增量,不用开机累计值比较不同机器 |
| `memory.max` | 该 cgroup 的硬上限,`max` 表示该层不设上限 | 与客体内存、当前用量、应用峰值和祖先边界一起核对 |
| `memory.events` | high/max/oom/oom_kill 等层级事件 | 比较同一工作负载窗口前后增量 |
用区间增量观察争用,不用一个累计数字定罪
Linux `/proc/stat` 把 steal 定义为非自愿等待,但单个样本或零值不能证明无争用。PSI 分别暴露 CPU、内存和 I/O 的 stall 时间;`some` 表示至少部分任务受阻,`full` 表示所有非空闲任务同时受阻。CPU 的系统级 `full` 没有可用含义,因此不能把它当 CPU 健康分数。
cg_rel=$(awk -F: '$1 == "0" { print $3 }' /proc/self/cgroup)
cg_dir="/sys/fs/cgroup$cg_rel"
date --utc --iso-8601=seconds
awk '$1 == "cpu" { print "steal_ticks=" $9 }' /proc/stat
sed -n '1,12p' "$cg_dir/cpu.stat"
for resource in cpu memory io; do
printf '%s ' "$resource"
sed -n '1,2p' "$cg_dir/$resource.pressure" | tr '\n' ';'
echo
done节流增加只说明本层在窗口内触及 CPU 带宽边界;steal 或 PSI 增加只说明发生了相应等待。它们帮助定位,不单独证明恶意超售。至少做空闲基线、受控候选负载和真实高峰三组,并在多日同一时段重复。
设备名称和介质标签不能替代存储路径验收
findmnt --json --target / | jq '.filesystems[0] | {target, source, fstype, options}'
stat -fc 'filesystem=%T block_size=%s' /
df --block-size=1 --output=source,fstype,size,used,avail,pcent,target /客体看到 `/dev/vda`、`/dev/nvme` 或某个型号,不足以证明物理介质、缓存、冗余和故障域。真正的验收应使用应用等价的块大小、并发、同步语义、数据集和持续时间,在可丢弃目录运行,并同时观察尾延迟、错误、空间和业务影响。
为每项基准写输入、停止条件和结论上限
| 对象 | 固定输入 | 可得结论 |
|---|---|---|
| CPU | 候选版本、线程数、数据集、持续时间 | 该窗口内的业务吞吐、耗时和调度指标 |
| 内存 | 工作集、并发、回收与 swap 状态 | 该工作集是否触发压力、节流或 OOM 事件 |
| 存储 | 目录、块大小、读写比、队列深度、同步方式 | 该路径在该负载下的吞吐与尾延迟 |
| 网络 | 真实客户端、协议、目标、方向、时段 | 该路径和时间窗的连接、吞吐、抖动与错误 |
- 先保存工具来源、版本、参数和校验值;网络下载的脚本先落盘审阅。
- 限制持续时间、空间、CPU、网络和费用;生产高峰不做首次压力测试。
- 同时记录空闲基线、候选负载和应用指标,失败立即停止。
- 不把单次峰值、平均值或第三方综合分数外推为 SLA、物理介质或未来容量。
不符合、未知和波动必须是三种结果
| 结果 | 示例 | 动作 |
|---|---|---|
| 不符合 | 架构错误、有效配额低于合同、候选不能启动 | 在验收窗口内保存证据并拒收、调整或迁移 |
| 未知 | 宿主超分比例、物理介质、故障域无法从客体证明 | 要求供应商材料或保持明确未知,不能填入猜测 |
| 波动 | 高峰 PSI/steal/延迟反复超出业务基线 | 扩大样本并关联真实请求,再决定容量或供应商动作 |
| 符合 | 合同、候选运行、压力窗口和恢复均通过 | 记录版本与时间,仅接受本次范围内结论 |
验收工单应包含原始输出摘要、UTC 时间、命令版本、套餐快照、候选 release、通过/失败规则和脱敏后的差异。不要公开主机名、地址、序列号、完整 CPU flags、挂载路径或许可证信息;必要时只提交给供应商的受限支持通道。
架构验收必须包含退出和恢复路径
- 确认控制台、救援环境、重装和快照权限不依赖客体 SSH。
- 在重要数据进入前,从独立备份恢复一个已知标记和应用候选。
- 记录跨 x86/ARM 或 VM/容器迁移时需要重建的镜像、包和数据格式。
- 任何压力测试前保存可恢复点,并明确停止、费用和数据清理责任。
- 拒收或迁移后删除实例、磁盘、快照、IP 和自动续费等残留资源。
本地演练证明了证据采集与契约拒绝
VPScope 在单台 Ubuntu 24.04 KVM 客体上使用 systemd 255 和 util-linux 2.39.3。`lscpu -J` 与 `uname -m` 都报告 x86_64、64 位和两个逻辑 CPU;检测器报告 KVM、没有容器信号。当前服务 cgroup 的 `cpu.max` 为 `150000 100000`,即 1.5 CPU 时间配额,内存硬边界为 2,621,440,000 字节;这直接展示了逻辑 CPU 数与有效配额为何必须分开。
一个受限 checksum 工作负载让 CPU 用量增加,steal 与 CPU PSI 增量保持可解析;CPU 节流、内存和 I/O 压力本轮可以为零,演练只验证计数器单调与采样逻辑。根文件系统被识别为 ext4,`/bin/true` 为 x86-64 ELF64;匹配契约退出 0,故意要求 aarch64、更多 CPU 和错误 ELF machine 的契约退出非零。临时目录已移除。演练没有访问物理宿主、供应商控制面、ARM、镜像仓库、公网或磁盘基准,也不证明 SLA、隔离、超售或应用容量。
VPS 架构验收的可复查清单
- 套餐中的架构、vCPU、内存、存储、网络、权限和恢复能力都有可判定规则。
- 客体架构、字长、逻辑 CPU 和实际候选发布物平台一致。
- 虚拟化检测按 VM/容器/嵌套解释,没有被当作宿主或隔离证明。
- 读取的是当前进程有效 cgroup;CPU 配额与逻辑 CPU 数分开记录。
- 内存硬边界、当前用量和 memory.events 在同一工作负载窗口核对。
- steal、节流与 PSI 使用区间增量,并与真实请求耗时和错误关联。
- 挂载源、文件系统和容量已识别;设备名称没有被当作物理介质证明。
- 基准固定工具、版本、参数、数据集、持续时间和停止条件。
- 不符合、未知、波动和符合分别记录,没有用综合分数掩盖未知。
- 候选应用在目标实例真实启动并通过正向、反向和恢复检查。
- 证据包已脱敏,供应商争议保留套餐快照、UTC 时间和原始摘要。
- 拒收、迁移和到期都有实例、磁盘、快照、IP、续费与数据清理清单。