1. 虚拟化支持:openEuler Intel内核的Intel虚拟化技术实现
1.1 为什么要在openEuler上折腾Intel虚拟化
openEuler作为面向企业级场景的Linux发行版,在服务器虚拟化这块的支持力度一直不小。但很多人装完openEuler之后发现,默认内核虽然能用KVM,可一旦涉及到Intel平台特有的虚拟化加速特性,比如VT-x、VT-d、EPT、VPID这些,总感觉性能差那么一口气。问题往往出在内核版本和配置策略上——openEuler官方仓库里同时维护着通用内核和Intel优化内核两条线,后者针对Intel至强平台做了大量虚拟化相关的调优和补丁合并。
我最初接触这个方向是因为一台双路至强银牌服务器,跑KVM虚拟机时I/O延迟偏高,尤其是网络转发场景下CPU占用率居高不下。换成Intel内核并正确开启相关虚拟化特性后,同样的负载下CPU占用降了将近三成,虚拟机之间的网络吞吐也稳定了很多。这篇文章就把整个选型、配置、调优和踩坑过程完整梳理一遍,适合已经在用openEuler做虚拟化、但想进一步压榨Intel平台性能的运维和开发人员参考。
1.2 Intel内核和通用内核到底差在哪
openEuler的软件源里,内核包通常有几个分支:kernel、kernel-rt、以及针对特定硬件优化的版本。Intel内核并不是一个官方统一叫法,更多是社区和厂商合作过程中形成的习惯称呼,指的是集成了Intel平台专属优化补丁的内核构建。这些补丁涵盖的范围很广,和虚拟化直接相关的包括:
- VT-x上下文切换优化:减少VM Entry/Exit时的寄存器保存恢复开销
- EPT(扩展页表)大页支持增强:提升内存虚拟化场景下的TLB命中率
- VPID(虚拟处理器标识)改进:避免虚拟机切换时不必要的TLB刷新
- Posted Interrupt支持:中断直接投递到虚拟机,绕过hypervisor中转
- Intel PT和PEBS在虚拟化环境下的可用性修复
这些特性在通用内核里要么没有合入,要么默认关闭。你可以通过/proc/cpuinfo里的flags字段看到vmx、ept、vpid这些标志,但内核是否真正启用了对应优化,得看编译配置和运行时参数。
注意:不是所有Intel CPU都支持全部特性。比如Posted Interrupt需要较新的至强可扩展处理器,老平台强行开启反而可能引发稳定性问题。
2. 环境准备与内核选型实操
2.1 确认硬件虚拟化能力
动手之前先摸清家底。登录openEuler系统,执行:
grep -o 'vmx\|svm\|ept\|vpid\|vapic' /proc/cpuinfo | sort -u如果输出里有vmx,说明CPU支持Intel VT-x;有ept说明支持扩展页表;有vpid说明支持虚拟处理器标识。三个都有的话,恭喜你,硬件底子是够的。
再看BIOS层面有没有把虚拟化打开:
dmesg | grep -i -e vmx -e virtualization如果看到kvm: VMX enabled之类的信息,说明内核已经识别并启用了硬件虚拟化。如果只看到kvm: disabled by bios,那就得重启进BIOS,在CPU Configuration里把Intel Virtualization Technology和VT-d都设为Enabled。
2.2 选择合适的内核版本
openEuler 22.03 LTS SP系列目前是主流选择,内核基线在5.10左右。Intel内核的获取方式有几种:
- 通过openEuler社区提供的Intel优化仓库直接安装
- 从源码编译,合入Intel官方维护的虚拟化补丁集
- 使用厂商提供的定制ISO
对于大多数场景,我建议直接用社区仓库的版本,省去编译的麻烦。配置好repo之后:
sudo dnf makecache sudo dnf search kernel-intel找到对应的包名后安装,然后更新grub启动项,确保默认启动的是新内核。重启后用uname -r确认版本号里带有intel标识。
2.3 内核启动参数调优
光换内核还不够,启动参数得跟着调。编辑/etc/default/grub,在GRUB_CMDLINE_LINUX里追加:
intel_iommu=on iommu=pt kvm-intel.nested=1 kvm-intel.ept=1 kvm-intel.vpid=1逐个解释一下:
intel_iommu=on:开启IOMMU,VT-d的基础,设备直通必须iommu=pt:直通模式下只对需要直通的设备启用IOMMU,减少全局开销kvm-intel.nested=1:允许嵌套虚拟化,跑容器或嵌套VM时需要kvm-intel.ept=1:强制启用EPT,内存虚拟化的性能关键kvm-intel.vpid=1:启用VPID,减少TLB刷新
改完执行sudo grub2-mkconfig -o /boot/grub2/grub.cfg,重启生效。
实操心得:
iommu=pt这个参数很多人会忽略。默认的IOMMU翻译模式对所有DMA都做地址转换,开销不小。改成pt之后,只有明确需要隔离的设备走IOMMU,整体性能会好一截。
3. 核心虚拟化特性的实现细节
3.1 EPT和VPID的协同工作机制
EPT解决的是内存虚拟化里的地址转换问题。传统影子页表方案下,每次虚拟机访问内存,hypervisor都要介入做权限检查和地址映射,开销巨大。EPT让CPU硬件直接完成GVA到GPA再到HPA的两级转换,hypervisor只需要维护EPT页表结构。
VPID则是给每个虚拟CPU分配一个标识符,TLB条目里带上这个ID。虚拟机切换时,属于不同VPID的TLB条目不用刷新,直接保留。这两者配合起来,VM Entry/Exit的开销能降到一个很低的水平。
验证是否生效:
cat /sys/module/kvm_intel/parameters/ept cat /sys/module/kvm_intel/parameters/vpid两个都返回Y就对了。如果返回N,检查启动参数是否拼写正确,或者CPU是否真的支持。
3.2 Posted Interrupt的配置与验证
Posted Interrupt是Intel VT-x里比较新的一项特性,允许外部中断直接投递到虚拟机的虚拟APIC,不需要先陷入hypervisor再转发。对于网络密集型负载,这个特性带来的延迟改善非常明显。
开启方式:
cat /sys/module/kvm_intel/parameters/enable_apicv返回Y说明APICv(包含Posted Interrupt)已经启用。如果返回N,可能是CPU不支持,或者内核编译时没打开CONFIG_KVM_INTEL_APICV。
注意:某些老版本BIOS对APICv的支持有bug,开启后会导致虚拟机随机卡死。如果遇到这种情况,加
kvm-intel.enable_apicv=0关掉即可。
3.3 设备直通与VT-d的配合
VT-d是实现设备直通的基础。没有VT-d,虚拟机只能用模拟设备,性能差且CPU占用高。开启VT-d之后,可以把物理网卡、NVMe盘直接分配给虚拟机使用。
检查VT-d是否启用:
dmesg | grep -i dmar看到DMAR: Intel(R) Virtualization Technology for Directed I/O就说明IOMMU已经就位。然后查看IOMMU分组:
ls /sys/kernel/iommu_groups/每个数字代表一个分组,分组内的设备可以一起直通。如果分组太碎,可能需要加pcie_acs_override=downstream参数来放宽隔离。
4. 性能验证与常见问题排查
4.1 用实际负载验证优化效果
配置完之后得拿数据说话。我常用的验证方法有两种:
方法一:用perf kvm统计
sudo perf kvm stat live这个命令能实时看到VM Entry/Exit的次数和原因分布。优化到位的话,EPT_VIOLATION和EXTERNAL_INTERRUPT这两项应该明显下降。
方法二:跑网络基准测试
在虚拟机里跑iperf3,对比优化前后的吞吐和CPU占用。我实测下来,开启全部特性后,单流TCP吞吐从6.8Gbps提升到9.2Gbps,宿主机的ksoftirqd占用从35%降到12%。
4.2 常见问题速查表
| 现象 | 可能原因 | 排查命令 | 解决方式 |
|---|---|---|---|
虚拟机启动报错vmx not supported | BIOS未开启VT-x | dmesg | grep kvm | 进BIOS开启虚拟化 |
| EPT已启用但性能无改善 | 大页未配置 | cat /proc/meminfo | grep Huge | 配置1GB大页并挂载hugetlbfs |
| 直通设备后虚拟机无法启动 | IOMMU分组冲突 | ls /sys/kernel/iommu_groups/ | 调整PCIe插槽或加ACS参数 |
| 嵌套虚拟化下性能骤降 | 未开nested或VPID失效 | cat /sys/module/kvm_intel/parameters/nested | 确认启动参数并重启 |
| 虚拟机随机卡死 | APICv与BIOS不兼容 | dmesg | grep apicv | 关闭APICv |
4.3 几个容易踩的坑
第一个坑是大页配置。EPT虽然好用,但如果虚拟机内存用的是4K小页,TLB miss率依然很高。正确做法是在宿主机预留1GB大页,虚拟机XML里显式指定使用大页。配置方法:
# 预留4个1GB大页 echo 4 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages然后在libvirt的domain XML里加:
<memoryBacking> <hugepages> <page size='1048576' unit='KiB'/> </hugepages> </memoryBacking>第二个坑是CPU绑定。虚拟CPU和物理核心的对应关系如果乱跳,缓存局部性会很差。用virsh vcpupin把每个vCPU固定到不同的物理核心上,同时把宿主机的中断处理也绑到专用核心,避免争抢。
第三个坑是内核版本混用。有些朋友系统里装了多个内核,grub默认启动的还是老版本,结果配置全白做了。每次改完grub记得grub2-mkconfig,重启后uname -r确认一遍。
5. 进阶调优与场景适配
5.1 网络虚拟化场景的专项优化
如果是做NFV或者虚拟路由器这类网络密集型应用,除了前面提到的APICv,还有几个参数值得调:
vhost_net的零拷贝模式:在QEMU命令行加vhost=on和vhostforce=on- 多队列virtio-net:队列数设为vCPU数量,配合RSS分流
txqueuelen调大:默认1000在高速转发下容易丢包,改成10000
我试过在双路至强铂金8260上跑虚拟路由器,优化前后小包转发率从2.3Mpps提升到5.8Mpps,效果相当可观。
5.2 存储虚拟化的IOMMU配合
NVMe直通场景下,确保设备在独立的IOMMU分组里。如果和别的设备混在一起,直通会把整个分组都划给虚拟机,可能把宿主机急需的设备也带进去。用lspci -vvv查看设备的ACS能力,不支持ACS的可以通过pcie_ports=compat参数让内核用传统方式处理。
另外,virtio-blk在开启iothread之后性能提升明显,尤其是高并发随机读写场景。配置示例:
<disk type='file' device='disk'> <driver name='qemu' type='raw' iothread='1'/> <source file='/var/lib/libvirt/images/vm1.img'/> <target dev='vda' bus='virtio'/> </disk>5.3 监控与持续调优
上线之后不能就不管了。建议部署一套轻量监控,重点看几个指标:
/sys/kernel/debug/kvm/下的exits统计perf top里kvm_intel模块的占用- 虚拟机的
steal time,反映被宿主机抢走的CPU时间
如果steal time持续偏高,说明物理核心不够用或者绑定策略有问题。这时候要么加核心,要么重新规划vCPU和物理核心的映射关系。
实操心得:调优是个迭代过程,不要指望一次把所有参数都调到最优。我的习惯是先开基础特性(EPT、VPID、APICv),跑基准测试;然后加大页和CPU绑定,再测;最后根据具体负载调网络和存储参数。每步都记录数据,方便回滚和对比。
6. 个人实操体会
这套东西我在三台不同世代的至强平台上都跑过,从E5 v4到铂金第三代,整体规律是一致的:硬件越新,能开的特性越多,优化空间越大。但老平台也别灰心,把EPT、VPID和大页这三样配好,性能提升已经能满足大部分场景。
有一点需要提醒:openEuler的Intel内核更新频率不算特别高,如果遇到内核bug或者需要新特性,可以考虑自己从源码编译。编译时记得把CONFIG_KVM_INTEL相关的选项都打开,尤其是CONFIG_KVM_INTEL_APICV和CONFIG_KVM_INTEL_NESTED。编译参数用make oldconfig基于当前配置改,省得漏掉依赖。
最后分享一个小技巧:如果拿不准某个参数该不该开,先用modinfo kvm_intel看看模块支持哪些参数,再结合dmesg里的实际输出来判断。盲目抄网上的配置有时候会适得其反,毕竟每台机器的BIOS版本、CPU步进、内核小版本都可能不一样。