上一篇 下一篇 分享链接 返回 返回顶部

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

发布人:Minchunlin 发布时间:2025-08-18 11:21 阅读量:1130


凌晨 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 条)

  1. virsh domstats --cpu-total --balloon --block --perf all
  2. numactl --hardware + taskset -cp $(pgrep -f qemu-system)
  3. ethtool -S bond0 | egrep "err|drop"
  4. tc qdisc show dev br0 / tc -s qdisc show dev br0
  5. fio --name=rand --rw=randread --bs=4k --iodepth=32 --runtime=60 --numjobs=8 --filename=/testfile
  6. qemu-img check -r all vm.qcow2
  7. lvs -a 看 Thin Pool 与快照
  8. dmesg | egrep -i "vfio|iommu|nvme|oom"
  9. perf top/bpftool prog(在 eBPF VM 内)
  10. 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 实战方案可以直接复用。

目录结构
全文