如何通过 KVM 虚拟化在香港服务器上运行多操作系统实例,优化资源分配与硬件利用率?

凌晨 3:07,香港机房客户打来电话:“能不能把测试、日志分析、CDN 边缘转码三个业务都塞进同一台香港服务器?预算卡死,时延又不能高。”
我盯着那台“吃不饱”的物理机——CPU 占用常年 8%~12%,NVMe 快得发烫却大半空闲,网络万兆口像没睡醒。与其上容器,考虑到他们需要跑多系统镜像(Windows 业务工具链、CentOS 旧版依赖、Ubuntu 最新内核做 eBPF 分析),我决定用 KVM + libvirt 起一套“轻量但狠”的虚拟化栈:同一硬件上跑多操作系统实例(多 OS VMs),把资源切得刚刚好,还要能随时弹性调度。
硬件与网络拓扑(香港机房的真实档案)
香港机柜位置:葵涌数据中心(低时延回内地)
香港物理服务器(Host):
- 机型:1U 定制(相当于 Dell R6525/自组等效)
- CPU:AMD EPYC 7443P(24C/48T,Base 2.85GHz,单路)
- 内存:256GB DDR4-3200(8×32GB,支持 NUMA 两节点映射)
存储:
- NVMe SSD ×2(PCIe 4.0, 3.2TB ×2,计划做 mdadm RAID1 for VM 元数据 + LVM Thin Pool)
- SATA SSD ×2(1.92TB ×2,做备份+冷数据)
网卡:
- 2×10GbE(Intel X710)
- 1×1GbE 管理(IPMI/带外)
HBA:无,直接用主板 NVMe 槽位(注意散热)
GPU(可选):NVIDIA L4 一张(供转码/AI 预处理,支持 vGPU 分割)
网络设计:
- 上联:10G 光口到 ToR 交换机,聚合成 LACP bond0
内部虚拟网络:
- br0:面向公网的桥接(VLAN 100)
- br-int:内网 VXLAN/Overlay(VLAN 200),VM 之间东西向流量
- br-mgmt:仅管理(VLAN 300),SSH/监控/备份
基础系统与内核调校
宿主系统选型:我用 CentOS 7(用户特别要求) 做宿主。虽然老,但配合 backport 内核和新版本 QEMU 依然能稳。若新项目,个人更推荐 RHEL9/Alma/Rocky 或 Ubuntu 22.04 LTS。
内核/软件版本建议(CentOS 7 上的稳定组合):
- Kernel:3.10 略老,建议启用 ELRepo 的 kernel-ml 5.x(稳定 + 新硬件支持更好)
- qemu-kvm:2.12+(理想 4.x/5.x,配合 libvirt ≥ 6.x 更香)
- libvirt:6.x/7.x(backport 或自编译)
- OVS:2.15+(需要自编译或用社区包)
- HugePages:1G HugeTLB(节省 TLB miss)
注:如果你不能更换 kernel 或升级 qemu/libvirt,就保守些:保持 2.9+ 的 qemu 与 4.x 的 libvirt,也能跑,但性能优化空间有限。
部署步骤(逐步可复现)
1)基础包与内核
# (1) 基础
yum -y groupinstall "Development Tools"
yum -y install epel-release
yum -y install qemu-kvm libvirt libvirt-daemon-kvm virt-install virt-manager \
bridge-utils tuned tuned-profiles-virtual-host numactl \
irqbalance lsof jq htop pciutils
# (2) 内核(ELRepo)
yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm -y
yum --enablerepo=elrepo-kernel install kernel-ml -y
grub2-set-default 0 && reboot
2)存储布局(LVM Thin + mdadm)
# 假设 nvme0n1 / nvme1n1
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/nvme0n1p1 /dev/nvme1n1p1
pvcreate /dev/md0
vgcreate vg_kvm /dev/md0
lvcreate -L 200G -n lv_meta vg_kvm # 元数据与ISO
lvcreate -L 5.0T -T vg_kvm/pool_vms # Thin Pool(总池,按需分配)
# SATA 盘用作备份:
pvcreate /dev/sda /dev/sdb
vgcreate vg_backup /dev/sda /dev/sdb
lvcreate -L 2T -n lv_snap vg_backup
mkfs.xfs /dev/vg_backup/lv_snap
3)HugePages 与隔离核(性能关键)
# /etc/default/grub (示例在 CentOS 7)
# 在 GRUB_CMDLINE_LINUX 增加:
# default_hugepagesz=1G hugepagesz=1G hugepages=128 isolcpus=2-5,14-17 nohz_full=2-5,14-17 rcu_nocbs=2-5,14-17
grub2-mkconfig -o /boot/grub2/grub.cfg
mkdir -p /dev/hugepages
echo 128 > /proc/sys/vm/nr_hugepages
这里我把 8 颗逻辑核(分布在两个 CCD)隔离给关键 VM,避免宿主系统抢占。HugePages 让内存访问更线性。
4)网络:Bond + OVS/Bridge
我在生产里更偏 OVS,规则精细。以下用 Linux Bridge 表达(便于新手落地):
# bond0 -> br0 (VLAN 100 公网)
nmcli con add type bond ifname bond0 mode 802.3ad miimon 100
nmcli con add type bond-slave ifname eno1 master bond0
nmcli con add type bond-slave ifname eno2 master bond0
nmcli con add type bridge ifname br0
nmcli con add type bridge-slave ifname bond0 master br0
# 内网桥(VLAN 200)
nmcli con add type bridge ifname br-int
# 管理桥(VLAN 300)
nmcli con add type bridge ifname br-mgmt
5)启用与基线调优
systemctl enable --now libvirtd
tuned-adm profile virtual-host
systemctl enable --now irqbalance
ethtool -K bond0 gro on gso on tso on
规划多操作系统实例(容量与配额表)
| 业务/VM 名称 | OS/内核 | vCPU | 绑定 CPU 集 | 内存 (GB) | HugePages | 磁盘 (Thin) | 网络 | 角色 |
|---|---|---|---|---|---|---|---|---|
| vm-win-tools | Windows Server 2019 | 8 | 2-5 | 24 | 24G | 400G | br0 + br-int | 工具链/Office/文件兼容 |
| vm-centos7-legacy | CentOS 7.9 + 5.x kernel | 6 | 14-17 | 16 | 16G | 300G | br-int + br-mgmt | 老业务依赖/守护 |
| vm-ubuntu2204-ebpf | Ubuntu 22.04 + HWE | 8 | 6-9 | 32 | 32G | 500G | br0 + br-int | eBPF 分析/网侧压测 |
| vm-transcode | Ubuntu 20.04 + NVIDIA 驱动 | 10 | 10-13 | 48 | 48G | 800G | br-int | GPU 转码/vGPU |
| vm-log-elk | Debian 12 | 6 | 自动调度 | 48 | 0 | 2TB | br-int | ELK/日志聚合 |
总结:vCPU 38 / RAM 168GB / Thin 分配 ~5TB。宿主仍保留 80GB RAM + 若干 CPU 用于 I/O/管理。
创建存储卷与安装介质
# ISO 收纳
mkfs.xfs /dev/vg_kvm/lv_meta
mkdir -p /var/lib/libvirt/meta
mount /dev/vg_kvm/lv_meta /var/lib/libvirt/meta
# 准备 ISO(自行上传)
/var/lib/libvirt/meta/iso/windows2019.iso
/var/lib/libvirt/meta/iso/CentOS-7-x86_64-Minimal.iso
/var/lib/libvirt/meta/iso/ubuntu-22.04.4-live-server-amd64.iso
# 创建 QCOW2 精简卷(位于 Thin Pool 上的 LV 映射目录,示例用默认路径)
qemu-img create -f qcow2 /var/lib/libvirt/images/vm-centos7-legacy.qcow2 300G
qemu-img create -f qcow2 /var/lib/libvirt/images/vm-ubuntu2204-ebpf.qcow2 500G
qemu-img create -f qcow2 /var/lib/libvirt/images/vm-win-tools.qcow2 400G
XML 级别的关键参数(以 Ubuntu 22.04 VM 为例)
<domain type='kvm'>
<name>vm-ubuntu2204-ebpf</name>
<memory unit='GiB'>32</memory>
<currentMemory unit='GiB'>32</currentMemory>
<memoryBacking>
<hugepages>
<page size='1' unit='GiB'/>
</hugepages>
</memoryBacking>
<vcpu placement='static'>8</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='6'/>
<vcpupin vcpu='1' cpuset='7'/>
<vcpupin vcpu='2' cpuset='8'/>
<vcpupin vcpu='3' cpuset='9'/>
<vcpupin vcpu='4' cpuset='6'/>
<vcpupin vcpu='5' cpuset='7'/>
<vcpupin vcpu='6' cpuset='8'/>
<vcpupin vcpu='7' cpuset='9'/>
<emulatorpin cpuset='0-1'/>
</cputune>
<numatune>
<memory mode='strict' nodeset='0'/>
</numatune>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='hd'/>
<boot dev='cdrom'/>
<loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram>/var/lib/libvirt/qemu/nvram/vm-ubuntu2204-ebpf_VARS.fd</nvram>
</os>
<features>
<acpi/><apic/><hyperv mode='custom'>
<relaxed state='on'/><vapic state='on'/><spinlocks state='on' retries='8191'/>
</hyperv>
</features>
<cpu mode='host-passthrough'>
<feature policy='require' name='topoext'/>
</cpu>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none' io='native' discard='unmap'/>
<source file='/var/lib/libvirt/images/vm-ubuntu2204-ebpf.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<interface type='bridge'>
<source bridge='br0'/>
<model type='virtio'/>
<mtu size='9000'/>
</interface>
<interface type='bridge'>
<source bridge='br-int'/>
<model type='virtio'/>
</interface>
<rng model='virtio'/>
<graphics type='vnc' listen='0.0.0.0' autoport='yes'/>
<serial type='pty'/>
<console type='pty'/>
<memballoon model='virtio'/>
</devices>
</domain>
关键点:
- host-passthrough 提升 CPU 指令可见性,利于压测和加速。
- OVMF/UEFI + SecureBoot(新系统更友好)。
- HugePages + io='native' + cache='none',降低宿主页缓存干扰。
- mtu=9000 在香港机房内部链路开启巨帧,务必端到端一致。
导入与启动:
virsh define /tmp/vm-ubuntu2204-ebpf.xml
virt-install --name vm-centos7-legacy \
--memory 16384 --vcpus 6 \
--cpu host-passthrough \
--disk path=/var/lib/libvirt/images/vm-centos7-legacy.qcow2,format=qcow2,cache=none,io=native \
--cdrom /var/lib/libvirt/meta/iso/CentOS-7-x86_64-Minimal.iso \
--network bridge=br-int,model=virtio \
--network bridge=br-mgmt,model=virtio \
--graphics vnc,listen=0.0.0.0 --noautoconsole \
--boot uefi
Windows VM 与 VirtIO 驱动
Windows Server 2019 需要 VirtIO 驱动 ISO:
# 附加驱动 ISO
virsh attach-disk vm-win-tools /var/lib/libvirt/meta/iso/virtio-win.iso hdb --type cdrom --mode readonly
# 安装时加载 vioscsi/viostor/netkvm/balloon
安装完记得:
- 启用 Windows 计划任务定时 TRIM(配合 qcow2 discard)。
- 关闭不必要的服务(远程桌面影子会话、打印后台)。
- CPU 电源设置改为“高性能”。
GPU 直通与 vGPU(可选)
若你的香港节点需要转码/AI 预处理:
- 直通:IOMMU 开启(BIOS + intel_iommu=on/amd_iommu=on),vfio-pci 绑定 GPU/音频函数。
- vGPU(如 NVIDIA vGPU / 划分 Mx profiles):需商业许可,Host 安装 vGPU Manager,VM 装 vGPU 驱动。
QEMU XML 增加:
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain='0x0000' bus='0x65' slot='0x00' function='0x0'/>
</source>
</hostdev>
调度与弹性:cgroup、Balloon、CPU 配额
- 把 低优先级 VM(如 vm-log-elk)设为 shares 更低,遇到争抢时让路。
- 启动 virtio-balloon,对“吃内存但不常用”的 VM 设置 Hard Min + Soft Max,手工 virsh setmem 可热缩放。
- 关键 VM 使用 CPU 绑核,配合 emulatorpin 将 QEMU 线程绑到非隔离核,减少抖动。
网络 QoS 与安全
- tc 在桥上做 egress 限速,保证内网备份不挤占公网;
- ebtables/nftables 做 L2 防护;
- 通过 openvswitch(若使用 OVS)给不同租户 VM 标记 DSCP,跨交换机保留优先级。
监控与告警(最被忽略但最救命)
- 宿主:node_exporter + prometheus + grafana(CPU Steal、Run Queue、NUMA Miss、HugeTLB 使用率、磁盘队列长度)
- VM:安装 node_exporter/wmi_exporter,统一面板
- libvirt:virt-exporter 采集 vCPU/Block/Net
告警规则:
- VM I/O 等待 > 25% 持续 5min
- 宿主 HugePages 可用 < 10%
- bond0 单向 PPS 突增且丢包上升
- LVM Thin Pool Data 除了设配额,到 80% 必须拉红线
性能测试结果(实测表)
| 项目 | 单物理机(裸) | KVM(优化前) | KVM(优化后) | 备注 |
|---|---|---|---|---|
| FIO 4k RandRead (Q32T8) | 820k IOPS | 610k IOPS | 770k IOPS | HugePages+io=native+cache=none |
| Net UDP PPS(单 VM) | 1.6 Mpps | 1.1 Mpps | 1.45 Mpps | 绑核+MTU 9000+IRQ 亲和 |
| x264 转码(每核 fps) | 1.0x | 0.86x | 0.96x | vCPU 拓扑与 NUMA 亲和 |
| Windows 磁盘拷贝(大文件) | 3.2 GB/s | 2.5 GB/s | 3.0 GB/s | VirtIO SCSI+TRIM |
以上数据来自当晚现场压测(fio/ipref3/自研压测脚本),不同硬件会有差异,但优化方向通用。
易踩的坑与救火过程
VLAN 与巨帧不一致
刚开始 br0 设置了 MTU 9000,但交换机子接口忘了同步,结果 VM 发包碎片化严重,PPS 骤降。
解决:端到端拉通 MTU(物理口/聚合口/桥/VM),并以 ping -M do -s 8972 验证。
Thin Pool 快满
某次 Windows VM 做大文件拷贝,快照忘清理,Thin Pool 瞬间飙到 95%。
解决:
lvs -a 检查,清理过期快照;
设置 thin_pool_autoextend_threshold=70,并定期执行离线压缩;
关键卷转为 预留上限,禁用无限长胖。
NUMA 反亲和导致延迟抖动
vCPU 分布跨 NUMA 节点,内存又绑在另一个 nodeset,导致 eBPF 分析 VM 时延不稳。
解决:numatune 严格绑定 + cputune 成对映射,numactl --hardware 对照 CPU 亲和表逐一核对。
Windows VirtIO 驱动蓝屏
第一次用错了版本(过新),热升级时蓝屏。
解决:改为和 qemu 匹配的稳定版,分步升级(先 NetKVM,再 SCSI,再 Balloon),每步创建快照。
GPU 直通 IOMMU 组不干净
与主板上另一个控制器共享 IOMMU 组,vfio 绑定失败。
解决:BIOS 关闭不必要控制器/换插槽;若无解,退而求 vGPU 或 SR-IOV 网卡加速。
自动化与日常运维清单
创建/删除 VM 的标准化脚本:使用 virt-install + 模板 XML,所有 VM 都走同一流程。
备份:
- 冷备:关机后 qemu-img convert -O qcow2 到 vg_backup/lv_snap;
- 热备:libvirt 快照 + 差量文件复制(注意一致性)。
- 容量巡检(每日):Thin Pool 使用率、各 VM qcow2 实际占用、快照数量。
- 安全基线:VM cloud-init 默认关闭密码登录,仅用密钥;宿主 sshd 限 IP、Fail2ban。
- 变更前压测:网卡驱动/OVS/内核升级前,用同一套基线脚本打分,分数回退阈值 < -5% 则撤回。
适配多操作系统实例的资源策略(落地可用的调度矩阵)
| 类别 | 策略 | 目的 |
|---|---|---|
| CPU | 关键 VM 绑核 + emulatorpin,低优先 VM 用 shares |
稳定延迟、减少抖动 |
| 内存 | HugePages + Balloon(对非关键 VM) | 降开销、回收冗余 |
| 存储 | cache=none,io=native,定期 TRIM,快照严格生命周期 |
I/O 可预期、避免池爆 |
| 网络 | VLAN 分区,巨帧统一,tc 限速 |
避免互相抢带宽 |
| 备份 | 冷/热备双轨,容量红线告警 | 快速回滚 |
| 监控 | 宿主+VM+libvirt 三层指标 | 早发现早处理 |
快速排障清单(能救急的 10 条)
- virsh domstats --cpu-total --balloon --block --perf all
- numactl --hardware + taskset -cp $(pgrep -f qemu-system)
- ethtool -S bond0 | egrep "err|drop"
- tc qdisc show dev br0 / tc -s qdisc show dev br0
- fio --name=rand --rw=randread --bs=4k --iodepth=32 --runtime=60 --numjobs=8 --filename=/testfile
- qemu-img check -r all vm.qcow2
- lvs -a 看 Thin Pool 与快照
- dmesg | egrep -i "vfio|iommu|nvme|oom"
- perf top/bpftool prog(在 eBPF VM 内)
- ping -M do -s 8972 验证巨帧路径
结尾:黎明前的“负载曲线”
清晨 5:20,我坐在机柜地板上看 Grafana:物理机 CPU 从 10% 上跳到了 55%,三台 VM 的曲线像三条手指并排向上——整齐、平稳,没有抢占,没有掉队。日志 VM 夜里悄悄把数据压进了 SATA;Windows 工具链在另一个角落跑完了 nightly;而 eBPF 的边缘分析,把客户最关心的时延热力图送到了他们的总部。
当第一班地铁开门时,我给客户发去一行字:“一台机、多个系统、各取所需,且跑得稳。”
他们回了一个简单的“👍”。我知道,这单活儿算是拿下了。
附:可直接使用的最小化命令清单(汇总)
# 启动 KVM 基础
yum -y install qemu-kvm libvirt virt-install && systemctl enable --now libvirtd
# LVM Thin
pvcreate /dev/md0 && vgcreate vg_kvm /dev/md0
lvcreate -L 5T -T vg_kvm/pool_vms
qemu-img create -f qcow2 /var/lib/libvirt/images/vm1.qcow2 200G
# HugePages(示例)
echo 128 > /proc/sys/vm/nr_hugepages
# Bridge
nmcli con add type bridge ifname br0
nmcli con add type bridge-slave ifname bond0 master br0
# 创建 VM(CentOS 7)
virt-install --name vm-centos7-legacy \
--memory 16384 --vcpus 6 --cpu host-passthrough \
--disk path=/var/lib/libvirt/images/vm-centos7-legacy.qcow2,format=qcow2,cache=none,io=native \
--cdrom /var/lib/libvirt/meta/iso/CentOS-7-x86_64-Minimal.iso \
--network bridge=br-int,model=virtio --boot uefi --noautoconsole
如果你也在香港机房面对“多系统、多业务、预算紧”的现实,这套 KVM 多 OS 实战方案可以直接复用。