ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ZSvirt虚拟化引擎架构拆解:KVM之上的生产级设计

ZSvirt虚拟化引擎架构拆解:KVM之上的生产级设计 ZSvirt 这个名字圈内人可能还觉得陌生但它的架构设计思路值得拿出来好好聊聊。一句话概括这是一套跑过真实业务流量、扛过故障演练、在资源隔离和性能之间反复拿捏过的虚拟化引擎。如果你正在做云平台底座或者正打算从零构建一套内部的虚拟化调度系统这篇拆解能让你少走不少弯路。虚拟化引擎这事儿原理上大家都懂无非是 CPU 虚拟化、内存虚拟化、I/O 虚拟化这几个大模块。但真正到了生产环境问题永远是细节CPU 在重度超卖时为什么会有抖动内存大页为什么有时候反而拖慢性能IO 线程为什么总是成为瓶颈这些课本上讲不清楚的东西才会真正决定一套架构能不能经受住生产检验。而这正是 ZSvirt 这套引擎最有参考价值的地方——它没有追求花哨的新技术而是把每一层的基础能力打磨到了适合生产交付的程度。这篇文章适合三类人读准备搞虚拟化平台开发的工程师、正在做服务器虚拟化选型或调优的运维以及那些想弄清楚虚拟化引擎到底在解决什么问题的技术管理者。我把整体架构思路、核心模块的设计取舍、生产环境里的实操配置以及我踩过的坑都整理出来尽量讲透。1. 从零搭建虚拟化引擎整体架构要怎么拆很多人一想到自研虚拟化引擎第一反应就是去动内核、改 KVM或者干脆自己写个 Hypervisor。ZSvirt 的路线完全相反底层老老实实基于 KVM 做把真正的功夫花在 KVM 之上的引擎层、调度层、可观测性层。这看起来不够硬核却是生产系统最稳的落地路径。1.1 为什么选 KVM 作为底座而不是自研内核方案自研 Hypervisor 的诱惑一直存在尤其是想追求极致性能或者做差异化功能的时候。但现实是一套 Hypervisor 不仅要处理指令调度、内存管理、中断控制这些底层逻辑还要跟着 CPU 厂商的微码更新、安全补丁不断迭代。Linux KVM 在这条路上已经走了十几年内核社区对 Intel VT-x 和 AMD-V 的支持成熟度远超任何一家公司的自研能力。ZSvirt 选择 KVM本质上是在做一个继承决策我不需要重新发明 CPU 虚拟化我需要的是把 CPU 虚拟化之外的事情做到极致——虚拟机生命周期管理、资源调度策略、故障隔离、安全加固、监控告警。这些才是业务侧真正感知得到的东西。这里也体现了一个很重要的架构原则控制面和数据面分离。KVM 负责数据面的指令执行和内存映射ZSvirt 引擎负责控制面的编排调度。控制面可以做成中心化的管理集群数据面均匀分布在计算节点上两者通过消息队列和分布式状态存储解耦。这样设计的好处很明显控制面挂了不影响正在运行的虚拟机数据面节点故障也可以在控制面重新调度恢复。1.2 架构分层引擎层、调度层、接入层各自管什么ZSvirt 的逻辑架构可以清晰地分成三层。最底下是引擎层直接和 KVM 打交道负责 vCPU 的创建与绑定、内存的映射与巨页配置、virtio 设备的初始化、PCIe passthrough 等。这层不关心业务只把虚拟机的运行环境构建好。引擎层还负责处理 KVM 的ioctl调用管理 VM fd 和 vCPU fd这一层处理不好后面什么都白搭。中间是调度层这是 ZSvirt 的核心竞争力所在。调度层维护每一个计算节点的资源水位包括 CPU 的物理核占用情况、内存剩余量、IO 带宽占用率。创建虚拟机时调度层会根据预设的策略比如装箱优先、负载均衡优先、故障域隔离选择最合适的宿主机。调度层还负责热迁移的决策和流量切换保证迁移过程中业务不感知。最上面是接入层面向云平台或内部 PaaS 系统提供接口。接入层收到创建虚拟机的请求后做参数校验、租户隔离检查、配额扣减然后通过调度层下发给具体节点的引擎层。接入层还会处理网络配置——虚拟交换机、安全组规则、负载均衡策略都在这个环节注入。这套三层架构单独看每一层都不复杂难的是层与层之间的数据一致性和故障传递机制。ZSvirt 在每层之间都做了超时熔断和重试队列避免控制面风暴打垮数据面。这个设计细节在生产环境里救过我们好几次。1.3 面向生产的三条设计底线隔离、稳定、可观测聊架构除了看功能模块更要看设计原则。ZSvirt 在设计之初就给自己定了三条底线这三个底线贯穿了后面所有的技术决策。第一条是隔离优先。虚拟化存在的意义就是隔离。CPU 要隔离——vCPU 的物理核绑定要可行不绑定时内核调度器不能把两个对性能敏感的虚拟机调度到同一个物理核上内存要隔离——不同虚拟机的内存页不能互相踩踏这要靠 EPT 和页表隔离来保证磁盘 IO 和网络 IO 也要隔离——某个租户疯狂刷盘不能把同一块物理盘上的其他虚拟机拖死。ZSvirt 在 IO 隔离上使用了 Cgroup 的 blkio 和网卡的 TC 队列严格限制每个虚拟机的 IOPS 和带宽。第二条是稳定压倒一切。虚拟化引擎最怕的不是慢而是挂。一个节点挂掉可能影响几十个虚拟机这在生产上是灾难性的。ZSvirt 对稳定性的要求细化到每个模块内存热插拔的失败回滚、热迁移中断后的源端状态恢复、IO 线程异常后的自动重建。所有这些都有明确的降级路径保证虚拟机进程不会被一个异常直接拖垮。第三条是可观测性内建。一个跑着几百个虚拟机的集群如果没有细粒度的监控数据出问题时就是瞎子摸象。ZSvirt 从第一个版本就在引擎层埋了丰富的指标每个 vCPU 的 steal 时间、EPT 缺页次数、IO 队列深度、内存回收延迟。这些指标通过 Prometheus 协议暴露出来。这套可观测性体系在后来的故障排查中发挥了决定性作用具体案例后面细讲。2. 核心模块拆解CPU、内存、IO 三大件怎么落地虚拟化引擎说一千道一万核心就三件事CPU 虚拟化、内存虚拟化、I/O 虚拟化。ZSvirt 对这三部分的处理既有对 KVM 默认行为的继承也有大量生产环境驱动的自定义优化。2.1 CPU 虚拟化从 VMCS 到 vCPU 调度CPU 虚拟化的底层是硬件辅助虚拟化。Intel 的 VT-x 和 AMD 的 SVM 都提供了 VMX 指令集和 VMCS 数据结构。每当虚拟机执行特权指令或者发生中断时CPU 会从非根模式切换到根模式KVM 捕获这个切换处理完后再通过 VMRUN/VMLAUNCH 回到客户机。这个过程叫 VM-Exit频率过高会严重拖慢性能。ZSvirt 在 CPU 虚拟化上的功夫主要不在 VMCS 管理而在 vCPU 的调度策略。KVM 本身提供了 vCPU 线程的概念这个线程被 Linux 内核调度器当作普通线程对待。问题就在这里普通线程的调度器不知道哪些 vCPU 是延迟敏感的哪些虚拟机之间有亲和性要求。ZSvirt 的调度层做了一个轻量级的资源画像系统。每个虚拟机在创建时可以声明自己的 CPU 敏感度等级延迟敏感型比如数据库节点、吞吐敏感型比如批量计算任务、低优先级型比如测试环境。调度层根据这些画像来做物理核分配。延迟敏感型的虚拟机优先绑定到独立的物理核上并且开启 CPU 独占不参与 CPU 超卖。吞吐敏感型的虚拟机可以共享物理核但会限制每个核上绑定的 vCPU 数量。还一个很多人容易忽略的点是 NUMA 亲和性。现在服务器都是多路 CPU 架构内存访问跨 NUMA 节点时延会显著增加。ZSvirt 在分配 vCPU 和内存时会尽量保证同一个虚拟机的 vCPU 和内存落在同一个 NUMA 节点上。如果某个虚拟机的内存容量超过单 NUMA 节点的总量会优先保证 vCPU 所在的 NUMA 节点内存靠近避免交叉访问。这个优化在内存密集型业务上效果非常明显时延可以降低 20% 到 30%。2.2 内存虚拟化EPT 与 1G 巨页的实战组合内存虚拟化经历了软件模拟、影子页表、硬件 EPT/NPT 三个阶段。现在的处理器都支持 EPTExtended Page Tables虚拟机访问物理内存时会经过两次地址转换客户机虚拟地址通过客户机页表转换为客户机物理地址再通过 EPT 页表转换为主机物理地址。两次转换都由 CPU 的 MMU 硬件完成性能损耗很低。但 EPT 页表的维护是有代价的。每次虚拟机发生缺页KVM 都要更新 EPT 页表这个操作需要捕获 VM-Exit代价不小。为了减少 EPT 缺页次数最佳实践就是使用大页内存。ZSvirt 默认启用 1G 巨页而不是常见的 2M 巨页。原因很好理解1G 巨页可以将 EPT 页表的覆盖范围扩大 512 倍极大降低缺页频率和页表遍历层级对内存访问密集型的虚拟机提升非常显着。当然 1G 巨页不是没有代价的。它对宿主机内存的连续性要求很高如果物理内存碎片化严重可能导致巨页分配失败。ZSvirt 的做法是宿主机上电后提前预留一个巨页池预留的内存在系统层面就通过内核参数 hugepagesz1G 和 hugepagesN 锁定。预留后这部分内存不能用作普通页面分配但可以保证虚拟机创建时内存的供给速度。内存热插拔是生产环境下容易被忽略的需求。数据库扩容、缓存节点扩容都需要在不中断业务的情况下增加内存。ZSvirt 在内存热插拔的设计上采用了多阶段策略先在客户机操作系统层面识别新内存做内存对齐检查再通过 ACPI 设备事件通知客户机最后由客户机内核完成内存块的 online 操作。这个流程任何一个环节失败ZSvirt 都会回滚内存设备的插拔动作保证虚拟机状态的一致性。2.3 I/O 虚拟化virtio 多队列与中断控制I/O 虚拟化是虚拟化引擎里最容易成为瓶颈的地方。早期的全虚拟化方式是设备模拟纯软件模拟网卡和磁盘性能差到没法用。半虚拟化 virtio 协议解决了大部分性能问题。virtio 的核心思路是让客户机知道自己是虚拟机直接使用与 Hypervisor 共享的环状队列进行通信省去了设备模拟的开销。ZSvirt 在 virtio 上的优化集中在多队列和中断合并两个方向。每个 virtio-net 设备可以配置多个队列对queue pair宿主机的每个物理网卡多队列配合多 vCPU可以实现网络流量的并行处理。默认情况下一个 4 vCPU 的虚拟机ZSvirt 会分配 4 个队列对vCPU 和队列之间建立一一绑定关系。这样网络收包时数据包经过宿主机的多队列网卡可以直接分发到对应队列再让对应的 vCPU 处理避免跨 CPU 访问带来的锁竞争。中断控制也是一个关键细节。虚拟机收到网络包时virtio 设备会产生中断通知客户机。如果中断过于频繁CPU 会被中断风暴淹没。ZSvirt 启用了中断合并机制不在每个包到达时立即中断而是累积一定数量或者超过一个短时间窗口一般是几十微秒后才统一注入中断。这个机制在高速小包场景下尤其有用实测能够将虚拟机 CPU 利用率降低 10% 到 15%。存储虚拟化的处理略有不同。virtio-blk 的全模拟路径性能已经不错但对极高性能的存储场景仍不够。ZSvirt 支持将物理 NVMe SSD 通过 PCIe passthrough 直接分配给虚拟机使用。这样虚拟机直接驱动物理 NVMe 控制器完全绕过宿主机内核的 IO 栈和 virtio 协议开销延迟可以做到微秒级。代价是一块物理盘只能给一个虚拟机用灵活性差。ZSvirt 的调度器会在创建虚拟机时判断存储性能需求超过阈值才走 passthrough其余情况走 virtio-blk 共享路径。2.4 存储与网络的额外加固存储层面最怕的是 IO 抖动。同一块物理磁盘上一个虚拟机的密集型写入会拖慢所有邻居。ZSvirt 在 cgroup blkio 的基础上加了 IO 权重调度每个虚拟机按照配置的权重比例获得 IO 带宽。权重模式比固定上限模式友好得多——整体负载低时某个虚拟机可以爆发使用全部带宽整体负载高时自动按比例收缩。这个机制既保证了公平又不浪费闲时的硬件能力。网络层面则做了流量整形和问题的边界收敛。每个虚拟机的虚拟网卡都挂到一个 OVS 桥上并通过 OVS 的 QoS 规则做带宽限制。ZSvirt 的接入层在创建网络配置时会一并计算当前物理网卡的带宽占用率如果超过安全水位比如 70%会把新虚拟机调度到其他节点。网络异常时ZSvirt 会自动触发网卡队列的健康检查发现某个队列长期阻塞后会重置该队列而不影响其他队列的正常工作。3. 实操记录一次完整的生产节点配置过程光讲架构不过瘾我直接把一次生产节点的配置过程记录下来。这次的业务模型是跑一套分布式数据库集群外加若干无状态前端应用要求虚拟机延迟低、IO 稳定。3.1 硬件与系统层准备硬件是两台双路服务器每颗 CPU 有 32 个物理核总共 64 核内存 512GB磁盘为四块 NVMe SSD 组成的 RAID10。BIOS 层面开启 VT-x或 AMD-V、VT-d 以及 SR-IOV 相关开关。这一项很多人会漏特别是服务器出厂设置可能默认关闭后面创建虚拟机时遇到硬件虚拟化不支持的错误基本都是这里的问题。系统层面需要配置内核参数和模块加载。建议在 /etc/default/grub 中加入以下参数GRUB_CMDLINE_LINUXintel_iommuon iommupt hugepagesz1G hugepages128 transparent_hugepageneverintel_iommuon 开启 IOMMU 用于 PCIe passthroughiommupt 是 passthrough 模式hugepagesz1G 和 hugepages128 预留 128 个 1G 巨页共 128GB。transparent_hugepagenever 表示关闭透明大页避免内核在运行时动态分配巨页带来的不确定性和内存碎片化。更新 grub 后重启重启后检查巨页是否预留成功$ cat /proc/meminfo | grep Huge HugePages_Total: 128 HugePages_Free: 128 Hugepagesize: 1048576 kBHugePages_Total 为 128每个巨页大小 1GB说明预留成功。注意如果 HugePages_Free 始终小于 Total说明有进程在占用巨页需要排查具体占用者后再做虚拟机创建操作。3.2 创建虚拟机时如何选择 CPU 和内存参数CPU 和内存参数的选择直接影响虚拟机的性能表现不能盲目套用模板。这里以一台用于数据库节点的虚拟机为例规划 16 vCPU、64GB 内存。创建前先用 numactl 检查一下 NUMA 拓扑$ numactl --hardware available: 2 nodes (0-1) node 0 cpus: 0-31 node 0 size: 262064 MB node 1 cpus: 32-63 node 1 size: 262016 MB机器是双 NUMA 节点每节点 32 核 256GB 内存。为了让数据库虚拟机的 64GB 内存和 16 vCPU 尽量落在同一个 NUMA 节点我建议绑定 node 0。这样不需要跨 NUMA 访问内存延迟最低。对应的 libvirt 域配置中简化版domain typekvm vcpu placementstatic16/vcpu cputune vcpupin vcpu0 cpuset0/ vcpupin vcpu1 cpuset1/ vcpupin vcpu2 cpuset2/ vcpupin vcpu3 cpuset3/ vcpupin vcpu4 cpuset4/ vcpupin vcpu5 cpuset5/ vcpupin vcpu6 cpuset6/ vcpupin vcpu7 cpuset7/ vcpupin vcpu8 cpuset8/ vcpupin vcpu9 cpuset9/ vcpupin vcpu10 cpuset10/ vcpupin vcpu11 cpuset11/ vcpupin vcpu12 cpuset12/ vcpupin vcpu13 cpuset13/ vcpupin vcpu14 cpuset14/ vcpupin vcpu15 cpuset15/ /cputune memory unitGiB64/memory memoryBacking hugepages page size1 unitGiB/ /hugepages /memoryBacking numatune memory modestrict nodeset0/ /numatune cpu modehost-passthrough cache modepassthrough/ topology sockets1 dies1 cores16 threads1/ /cpu /domainvcpupin 把每个 vCPU 绑定到 node 0 的物理核numatune 的 strict 模式强制内存从 node 0 分配。CPU 选择 host-passthrough 模式而非常见的 host-model是为了让客户机的 CPU 特性完全等同于宿主机避免某些指令在客户机里缺失导致应用兼容性问题。cache passthrough 则是把宿主机的 CPU 缓存拓扑暴露给客户机这对一些对缓存敏感的应用比如 Redis很有帮助。内存使用 1G 巨页会让 KVM 给客户机的内存映射走 1G 大页路径EPT 缺页次数会大幅下降。数据库在这台虚拟机上跑起来后内存访问延迟比之前用 2M 巨页时降低了大约 15%。不过要注意1G 巨页的预留是固定占用的如果虚拟机实际用不到这么多内存就会造成宿主机内存浪费需要在容量规划时算清楚。3.3 虚拟化引擎要全开吗逐项分析那些加速开关这是我在后台被问得最多的问题。很多人说客户机操作系统里有虚拟化引擎设置Windows 的 Hyper-V 或一些安全软件会提示虚拟化安全是否启用Linux 客户机里也经常看到 KVM、vhost、virtio 相关的开关。到底哪些该全开哪些要权衡先说结论不是所有开关都适合全开要区分场景。CPU 层面的硬件虚拟化VT-x/AMD-V是必须开启的这是虚拟化的基础设施不存在不开启的选项。如果你是在虚拟机里再跑一层虚拟机嵌套虚拟化那在物理层要开启嵌套虚拟化支持但嵌套虚拟化本身性能代价比较大生产环境除非有明确需求比如在虚拟机里测试另一套虚拟化平台否则不建议全开。vhost-net 半虚拟化加速要分场景。vhost-net 把 virtio 的数据通路从用户态搬到了内核态减少了用户态与内核态的切换次数和内存拷贝。开启 vhost-net 后网络吞吐有明显提升CPU 占用显著下降。这个开关建议全开但对延迟极为敏感的 DPDK 型应用场景除外因为 vhost-net 的内核处理路径多了协议栈开销这时走 userspace vhostvhost-user反而更合适。NUMA 相关的自动均衡开关要谨慎。Linux 内核的 NUMA balancing 会定期把内存页迁移到访问它的 CPU 所在节点这对一般应用是好事。但在虚拟化场景下虚拟机的内存是连续大页分配而 vCPU 已经被钉在固定的物理核上让内核 NUMA balancing 自动迁移反而可能破坏大页的连续性。ZSvirt 的做法是关闭客户机内核的 NUMA balancing完全由宿主机调度层做 NUMA 亲和性控制。IOMMU 的开关则取决于是否做 PCIe passthrough。如果不用 passthrough可以关闭 IOMMU 以减少虚拟 IO 路径的地址翻译开销。但关闭 IOMMU 也意味着你不能用 VFIO 做设备直通后续如果有高性能存储或网卡需求就没法满足。所以我的建议是规划了高性能裸设备需求的节点保留 IOMMU 开启纯做通用计算的节点可以关闭。总结一下各开关的参考选项可以存下这张表开关/选项适用场景建议VT-x/AMD-V所有虚拟化场景必开嵌套虚拟化仅测试或开发环境默认关闭vhost-net通用网络虚拟化全开vhost-userDPDK、SRIOV 高吞吐低延迟按需开启NUMA balancing一般应用虚拟化场景建议关闭IOMMU需要 PCIe passthrough按需开启1G 巨页内存密集业务生产优先CPU host-passthrough追求指令集完整兼容推荐3.4 监控与告警体系怎么证明系统是健康的生产环境的虚拟化引擎没有监控就等于裸奔。ZSvirt 的监控指标分三层宿主机层、虚拟机层、业务层。宿主机层主要看 CPU steal 时间、内存分配延迟、巨页剩余、网卡丢包率、存储 IO 队列深度。CPU steal 时间是判断宿主机是否超卖过度的最重要指标——如果虚拟机内部的 CPU 使用率不高但应用就是慢大概率是 steal 时间过高说明 vCPU 在等待物理核调度。虚拟机层关注 vCPU 的调度延迟、内存缺页率、virtio 队列积压。这些指标通过在每个计算节点上部署的 agent 采集通过 Prometheus 汇总到 Grafana 展示。告警规则要细化比如某个虚拟机的 EPT 缺页次数突然上涨 5 倍说明它开始频繁访问新分配的匿名内存页需要排查是不是内存压力过大导致的。业务层告警反而是最重要的兜底。任何一个监控指标都有可能出现假阴性即指标看起来正常但业务已经受损。ZSvirt 在每个虚拟机上部署了一个轻量的探针服务定时做一次 TCP 重连或 HTTP 健康检查通过虚拟化引擎的带外通道上报状态。一旦业务侧探针异常优先触发业务告警然后再结合监控数据回溯原因。这套业务探针 基础设施监控的组合是我们处理故障时最可靠的信息来源。4. 生产环境故障排查与调优实录架构设计再完美生产环境总会有意外。这一部分我挑几个真实遇到的典型案例复盘排查思路和解决办法。每一条都是花了真金白银买来的教训。4.1 问题定位方法论先看数据再动配置虚拟化环境的问题定位有个很大的陷阱问题现象往往在客户机内部但根源在宿主机层面。比如虚拟机里的数据库突然 query 变慢DBA 第一反应是 SQL 执行计划变了查了半天找不到原因实际上可能是 vCPU 的 steal 时间飙升导致所有线程都在等 CPU 调度。所以我一直强调要先看数据、再动配置。排查问题时按这个顺序来先看业务探针的告警时间点再看虚拟机层的监控指标CPU steal、内存缺页、IO 等待最后看宿主机层的资源水位和内核日志。如果虚拟机和宿主机指标都正常才去怀疑应用层本身的问题。这套方法论严重减少了瞎猜的次数。实际排查时一个很有用的命令是 virsh vcpuinfo 配合 /proc/stat 观察 vCPU 线程的调度延迟$ virsh vcpuinfo zsvirt-db01 VCPU: 0 CPU: 5 State: running CPU time: 123.4s如果发现 VCPU 对应的物理核在频繁变化State 是 running 但 CPU 列经常不同说明 vCPU 在做物理核迁移TLB 亲和性被破坏性能一定会受损。这种情况就回去检查 vcpupin 配置是否被某些宿主机维护操作给覆盖了。4.2 我踩过的几个典型坑第一个坑透明大页导致的延迟毛刺。有段时间一个延迟敏感型虚拟机频繁出现毫秒级抖动排查 CPU 和存储指标都正常。后来通过 perf 分析宿主机内核发现透明大页在后台做内存规整compaction这个过程会大量尝试迁移内存页导致管理程序连续性中断。最终解决方法是彻底关闭透明大页并预留 1G 巨页给虚拟机专用。从那以后所有 ZSvirt 节点都默认关闭透明大页再也没有出现这类毛刺。第二个坑vhost 线程的 CPU 亲和性没设置。virtio-net 使用 vhost 线程处理半虚拟化数据通路。如果宿主机上有多个虚拟机都在跑网络流量vhost 线程之间会互相竞争 CPU 资源导致吞吐突然掉底。解决方法是给每个 vhost 线程绑定独立的物理核尤其要避免和 vCPU 线程抢同一个核。设置方式是在虚拟机 XML 中加入 的 vhost 线程 pin 配置把 vhost 线程钉在物理核 16-23 这一组专属区域内。第三个坑多路径存储的 IO 路径不对称。在一个使用了 SAN 存储的环境里宿主机配置了多路径multipath但部分路径的性能差异极大。虚拟机的 IO 随机分配到慢路径上就出现有时候快有时候慢的诡异现象。ZSvirt 的做法是在存储层加了一个 IO 路径健康度检测模块定期用 fio 探测所有可用路径的延迟并让调度器将虚拟机的 IO 请求固定到最低延迟的路径上。这个调优让数据库虚拟机的 P99 延迟降低了将近一半。第四个坑定时任务导致的 CPU 风暴。这个坑来自业务侧而非虚拟化引擎本身。某天一个节点上的所有虚拟机同时出现 CPU 使用率飙升但每个虚拟机内部的业务负载并不高。最后查出来是宿主机的 cron 任务在同一时刻触发了系统审计日志的滚动压缩占满了所有磁盘 IO 和部分 CPU。从那以后ZSvirt 的计算节点规定禁止在业务高峰期安排宿主机的巡检、日志清理、补丁更新任务。这类系统级操作也要纳入变更管理流程不能随意设置。4.3 快速排查手册虚拟化问题速查表现象可能原因排查命令/手段解决办法虚拟机内部 CPU 高但性能低vCPU steal 时间过长客户机执行 top/pidstat查看 %steal减少宿主机的 CPU 超卖绑定物理核网络吞吐忽高忽低vhost 线程竞争 CPU宿主执行 ps -eLo pid,tid,psr,comm | grep vhost给 vhost 线程绑定独立物理核内存敏感业务延迟抖动透明大页内存规整执行 cat /sys/kernel/mm/transparent_hugepage/enabled改为 never并用 1G 巨页虚拟机无法使用 PCIe 设备IOMMU 未开启或 ACS 路径问题执行 dmesg | grep -i iommu确认内核参数 intel_iommuon检查 PCIe ACS 开关热迁移后性能下降NUMA 亲和性被破坏执行 numactl --hardware 对比迁移前后拓扑开启迁移前 NUMA 校验确保目标节点拓扑相近磁盘 IO 延迟不稳定多路径 IO 路径不均衡执行 multipath -ll 查看路径状态配置路径组策略固定使用低延迟路径虚拟机创建卡住巨页耗尽或内存碎片化执行 cat /proc/meminfo | grep HugeFree预留充足巨页池必要时重启宿主机释放碎片客户机时钟漂移虚拟机缺少 kvm-clock客户机执行 dmesg | grep kvm-clock确保内核开启 kvm-clock 高精度时钟结尾一些自己的体会敲完这些内容我自己也回顾了一遍 ZSvirt 从设计到落地的全过程。一个虚拟化引擎能经受住生产检验除了底层技术选型要稳更关键的是工程层面的克制不追求每一项指标都是极致但做到每一项关键能力都有兜底。CPU 超卖率控制在合理区间、内存使用率绝不逼近物理上限、IO 压力分散到多路径上这些朴素的规则反而比任何精巧的算法都更能保证系统稳定。最后再分享一个小技巧如果你是第一次搭建自己的虚拟化平台不要一上来就把所有虚拟机的 CPU 内存配置拉满。先建一台最小配置的虚拟机跑生产业务持续观察一周的稳定性和性能指标把宿主机的监控告警调好再逐步扩容。慢慢来往往才是最快的。
返回列表