在租来的物理机上跑 GPU 训练、跑 DPDK 转发、跑低延迟存储,很多人第一步就卡在同一个地方:卡明明插在机器上,虚拟机里要么认不到,要么认到了跑不动。问题基本不在"性能不够",而在"路径不对"——数据面到底走不走宿主机内核。本文按一条真实部署顺序展开:先判断你是不是非直通不可,再拆开 virtio 转发链路与 VFIO 直通链路的差别,然后讲 IOMMU 分组这道硬门槛、GPU 直通的三种典型故障形态、SR-IOV 的 PF 与 VF 关系,并把直通之后你会失去哪些运维能力、以及双路机型上插槽与 NUMA 带来的隐性代价一并算清。
直通不是性能增强选项,它改变的是设备的归属关系。判断要不要上直通,先看业务到底需要设备的哪一层能力。
大模型训练依赖的不只是 CUDA core,还有 guest 内完整可见的驱动栈:nvidia 内核模块、持久化模式、NVLink 与 NVSwitch 拓扑、GPUDirect P2P 与 GPUDirect RDMA、以及 NCCL 对卡间通信路径的选择。这些能力建立在 guest 能看到真实 PCIe 设备、能读到完整 BAR 空间、能自行完成 DMA 的前提上。半虚拟化的 vGPU 方案是把一张卡按时间片或按显存分区切给多个虚机,guest 里跑的是另一套驱动模型,卡间 P2P 与拓扑可见性会被截断。多卡训练尤其是需要 NVLink 全互连的场景,通常只能整卡直通。
网关、防火墙、负载均衡、软路由这类业务,看重的不只是吞吐峰值,更是尾延迟和抖动。半虚拟化转发路径上,包的命运取决于宿主机后端线程的调度:线程什么时候被调度上来、vCPU 什么时候被抢占、跨 NUMA 的内存拷贝什么时候发生,都会变成延迟毛刺。对跑 DPDK、VPP、eBPF/XDP 这类用户态轮询转发的应用来说,轮询本身就是要绕开内核的,再在底下垫一层宿主机转发,等于把绕开的代价重新加回来。此时要的是虚机直接拿到网卡的硬件队列。
有些设备根本不存在可用的半虚拟化后端:加密卡、视频采集卡、FPGA 加速卡、特定型号的 NVMe 设备、需要专有工具链才能读状态的采集卡。这类设备的驱动只认真实 PCIe 配置空间和真实 BAR,厂商工具链也假设自己独占设备。它们没有"转发"这个选项,只能整体交出去。
反过来,Web 服务、普通数据库、中小流量应用、开发测试环境,virtio 半虚拟化往往更划算:它换来的是热迁移、快照、弹性伸缩和统一的宿主机监控,而这些正是租用场景下最实用的运维杠杆。要不要直通,本质是拿这四项能力去换数据面路径。
理解直通,最有效的方式是把两条链路一个环节一个环节画出来。
以 virtio-net 为例,guest 里的前端驱动(virtio_net)把待发送包的描述符填进 virtqueue——virtqueue 是三段共享内存环形结构:描述符表、available ring、used ring。前端填完描述符后,写一次设备寄存器做 kick,这个写操作会触发一次 vmexit,把控制权交回宿主机。宿主机侧由后端处理:vhost-net 是内核线程,vhost-user(搭配 DPDK/OVS-DPDK)是用户态进程,纯 QEMU 模式则由 QEMU 的 iothread 处理。后端从 virtqueue 取出描述符,把包送到 tap 设备、网桥或直接送到物理网卡,收包方向则反向走一遍:后端收包、填 used ring、向 guest 注入中断。
这条链路有三个代价点。一是通知开销:kick 与中断注入都会带来 vmexit 与 VM-entry,高频小包场景下占比显著;vhost 与事件机制(eventfd/irqfd)可以把一部分通知旁路掉,但数据面依然在宿主侧。二是调度抖动:后端线程与 guest vCPU 是两个调度实体,宿主负载高时后端线程排队,延迟抖动由此产生。三是拷贝与跨节点访问:共享内存页若落在与处理线程不同的 NUMA 节点,每次访问都要跨片。
virtio-blk 与 virtio-scsi 同理,只是后端落在宿主机的块层与文件系统上,且多了一层宿主缓存与 io_uring/线程池的调度。
VFIO 的做法是把设备的访问权交给用户态进程(QEMU),再由 QEMU 把设备的资源暴露给 guest。具体来说:QEMU 打开 /dev/vfio/{group} 取得设备访问权,把设备的 PCI 配置空间访问做中介(部分敏感配置空间由 QEMU 代理,避免 guest 破坏宿主需要的状态),把 BAR 空间通过 mmap 直接映射到 guest 的地址空间,再通过 IOMMU 为该设备建立 DMA 映射表。
结果是 guest 里装载的是这块卡的原生驱动——网卡就是 mlx5_core、i40e、ice 那一套,GPU 就是标准的 nvidia 驱动。这个驱动像在物理机上一样读写设备寄存器、下发描述符环、处理完成队列。数据面不再经过宿主机内核网络栈或块层,宿主机只承担配置与中断投递的辅助角色。
中断方面,直通设备产生的 MSI-X 中断由宿主机 IOMMU 的中断重映射单元接收,再通过 irqfd 一类机制注入 guest 的某个 vCPU(在硬件支持 Posted Interrupt 的平台上可以更直接地投递)。关键点在于:中断的语义是"设备告诉 guest 它的队列有进展了",宿主不再解析包内容,也不再决定这个包属于谁。
一句话概括:virtio 交换的是"数据",VFIO 交出的是"设备"。virtio 下 guest 与设备之间始终隔着一个宿主后端实体,这个实体既带来拷贝与调度,也带来了可控性与可迁移性;VFIO 下这个实体从数据面上消失了,guest 拿到接近裸机的行为,但宿主机从此对这块设备上发生的事情一无所知。后面所有运维代价,都源于"宿主机不再拥有这个设备"这一件事。
VFIO 敢把设备直接交给虚机,前提是硬件能保证这块设备的 DMA 只打到分配给它的那部分内存。这个保证由 IOMMU 提供:Intel 平台叫 VT-d,AMD 平台叫 AMD-Vi(IOMMU)。没有 IOMMU,或者 IOMMU 没开,DMA 使用的是物理地址,guest 若控制了设备就能读写任意物理内存,隔离无从谈起。VFIO 驱动在没有 IOMMU 的机器上也可以被强制使用,但那等于放弃了隔离保证,多租环境下不可接受。
实际开启涉及几个内核参数:Intel 平台是 intel_iommu=on,AMD 平台是 amd_iommu=on(多数发行版对 AMD 平台默认开启)。iommu=pt 是一个常见取舍:它让 IOMMU 只为分配给虚机的设备建立 passthrough 映射,宿主机自己驱动的设备绕过 DMA 翻译,从而避免宿主侧设备因为 DMA 地址转换而损失性能,同时保留直通需要的映射能力。若不加这个参数,所有设备的 DMA 都要走转换表,宿主机上的磁盘、网络会有可测量的开销。相对的,iommu.strict 之类的开关影响的是 TLB 失效策略与一致性强度,属于更细的调优项,一般不需要先动。
还要确认固件层:BIOS/UEFI 里必须有 VT-d / AMD-Vi / IOMMU 这一项且处于开启状态。很多租用机型出厂默认关闭,尤其是被用作普通云主机的机器。这一项不开,内核参数写了也不会生效,最直接的验证方式是看系统启动后 /sys/kernel/iommu_groups 目录是否存在且非空。
IOMMU 的工作单位是 group(组)。内核按 PCIe 拓扑的隔离能力,把"无法保证彼此 DMA 隔离"的设备划进同一个 group。VFIO 的规则非常明确:一个 group 内的所有设备,必须作为一个整体交给同一个虚机。你不能只把其中一块拿走,因为拿走之后,同组另一块设备的 DMA 仍能到达那块被拿走设备所能到达的内存区域,隔离边界已经破了。
这就引出了最常见的现场事故:一台机器上插了四张 GPU,你想把其中一张直通给某个虚机,结果发现这四张卡全在同一个 group 里,只能一起交出去。造成这种情况的通常是 PCIe 拓扑——多张卡挂在同一个 PCIe switch 或同一个下游桥之下,而这个桥对设备间的 peer-to-peer 传输不具备强制上送(redirect)的能力。
决定这个"能不能拆"的硬件特性叫 ACS(Access Control Services)。ACS 提供的是一组控制能力:PCIe 桥可以强制把下游设备之间的 peer-to-peer 请求上送到根复合体去裁决,而不是让两个设备私下直接通信;可以基于地址与 ID 做访问控制;可以阻断某些事务转发。具备 ACS 且在固件/驱动中启用的桥,其下游设备通常能被划进独立的 group。
问题在于:ACS 是否启用,取决于桥的硬件能力、固件是否打开对应位、以及内核是否对其做了修正。CPU 自带的根端口(root port)一般表现较好,而主板上的 PCIe switch 芯片、特别是 OEM 品牌整机与部分笔记本平台上,ACS 能力常常缺失或被固件关掉。这就是为什么很多人在 BIOS 里翻遍了也找不到 "ACS Enable" 这一项——它压根不是 BIOS 暴露给用户的标准选项,很多机型只提供 VT-d / SR-IOV Support / Above 4G Decoding 这几项,ACS 的开关要么不存在,要么隐藏在厂商的调试选项中。
现场核查有两个实用动作:一是用 lspci -vvv 看目标设备与其上游桥的 ACSCap 与 ACSCtl 字段,确认能力位与控制位;二是直接遍历 /sys/kernel/iommu_groups 下的每个组,列出组内所有设备,看你要直通的那张卡是不是"独占"一个组。这两个动作应该在下单前就要求机房协助确认,而不是上架之后才发现。
顺带一提,社区里有通过内核补丁强行放宽分组检查的做法(即所谓的 ACS override 补丁)。这种做法等于自己声明"我接受隔离被削弱",在单租户自己独占物理机、且不做不可信多租的前提下可以接受,但只要一块卡要交给不完全可信的一方,就不该用。
GPU 是直通里故障率最高的一类设备,因为它的驱动固件耦合最紧、对 PCIe 拓扑最敏感。三种故障形态几乎覆盖了九成现场问题。
现象是虚机内设备管理器或日志里出现 code 43,驱动加载后立刻拒绝工作。成因不在硬件,而在检测:部分驱动版本会在初始化时探测自己是否运行在虚拟环境中,并对特定产品序列做限制。这种限制针对的主要是消费级产品线(GeForce 系列),数据中心产品线在直通支持上走的是另一条路。
工程上的应对方向是"隐藏虚拟化痕迹":在虚机定义里把 hypervisor 相关特征关掉(KVM 的隐藏状态)、把 CPU 的 hypervisor 标志位去掉、给设备配置空间里的厂商 ID 字段做伪装,让驱动无法从这些通道判断自己身处虚机。这些都属于配置层面的处理,而不是绕过付费授权——需要明确的是,消费级卡在虚拟化场景下的授权边界由厂商条款决定,生产环境更稳妥的做法是直接选用数据中心卡。
第二种故障是虚机一启动就黑屏,或者卡在显存初始化阶段。GPU 与网卡不同,它在 guest 里被重置之后需要执行自己的 VBIOS(也就是卡的 Option ROM)来初始化显示输出与显存控制器。有些卡的 ROM 在虚机环境下不能正常被映射或执行,尤其是经过宿主使用、处于非初始状态的卡,或者 OEM 渠道的定制卡。
处理办法是手工指定 ROM 文件:先在宿主机上把卡的 ROM 读出来(在设备未被驱动接管、处于初始状态时读取最可靠),保存成文件,再在虚机配置里显式指定这个 ROM 文件路径,同时按需调整 rombar 相关设置。另一个常见的配套动作是"启动顺序"问题:某些卡要求虚机以特定固件(UEFI 而非传统 BIOS)启动,SeaBIOS 模式下 ROM 执行会失败。宿主如果在接管过这块卡之后没有做正确的复位就交给虚机,也会出现状态残留导致的黑屏,这时需要确认设备支持功能级复位(FLR)或总线复位。
第三种最容易被误判为"卡坏了":80GB 的卡在虚机里只认出很小一部分,或者干脆报 MMIO 分配失败。原因是地址空间。GPU 的显存是通过 BAR(Base Address Register)映射到系统地址空间的,大显存卡的 BAR 窗口非常大,传统的 32 位 MMIO 窗口(位于 4GB 地址以下)根本放不下。
需要打开的固件项是 Above 4G Decoding(有时也写作 Above 4GB MMIO / 64-bit MMIO),与之配套的还有 Resizable BAR 能力——后者允许设备在枚举阶段协商更大的 BAR 尺寸。A100、H100 这类大显存数据中心卡,如果 Above 4G Decoding 没开,MMIO 空间不够,直通后 guest 要么识别不到完整显存,要么直接无法初始化。这个开关位于 BIOS,同样必须在下单前确认机型是否开放给用户。它与 SR-IOV Support、VT-d 一起,构成了 GPU 直通机型必须确认的"固件三件套"。
两者在直通支持上的差别是产品定位层面的:数据中心卡(T4、V100S、A100、H100 这一序列)面向虚拟化场景设计,驱动与固件对直通、对 vGPU 切分的支持是明确的产品能力,大 BAR 与复位行为也更规范;消费级卡面向工作站,不提供官方虚拟化授权,前述的 code 43 检测就出在这条产品线上,且BIOS 行为在不同 OEM 渠道间差异很大。做生产训练与推理,选数据中心卡省下的是排查时间与合规风险。
如果说整卡直通是"把整块设备交出去",SR-IOV 就是"把一块设备拆成多块能独立交出去的设备"。
SR-IOV 在 PCIe 规范里定义了两类功能:PF(Physical Function,物理功能)与 VF(Virtual Function,虚拟功能)。PF 是完整功能的 PCIe 功能,拥有完整的配置空间和资源管理能力,由宿主机的原生驱动(PF 驱动)接管;VF 是从 PF 派生出来的轻量功能,只暴露数据面所需的最小寄存器集合,可以被独立地分配给虚机。
VF 不是凭空出现的,需要 PF 驱动配合创建。常见操作是向 sysfs 下的 sriov_numvfs 写入期望数量,网卡与 PF 驱动据此在硬件中实例化对应数量的 VF,随后这些 VF 会作为新的 PCIe 设备出现在 lspci 列表里。VF 的数量上限由网卡型号与驱动共同决定,常见为数个到数十个,不同型号差别很大,必须以厂商规格为准,不能想当然。
VF 的身份属性不是自己决定的,而是由 PF 驱动下发的:MAC 地址、VLAN ID、速率限制、防欺骗检查(spoofchk)、信任模式(trust)、链路状态等,都需要通过 PF 驱动提供的接口(例如 ip link 对 vf 参数的操作)配置。也就是说,VF 直通给 guest 之后,guest 拿到的是"能收发包的硬件队列",但"这块 VF 允许以什么身份发包"这件事,管理权仍留在宿主机的 PF 侧。这是 SR-IOV 相对整卡直通的一个关键差异:宿主机没有被完全排除在管理面之外。
VF 被通过 VFIO 交给虚机后,guest 装载的是这块网卡家族对应的 VF 驱动(不同厂商驱动名不同,如 i40e/iavf 系、mlx5 系等)。guest 得到的是真实的硬件队列:发送队列与接收队列在网卡里,描述符环由 guest 驱动直接管理,DMA 由 IOMMU 重映射后直通到 guest 内存,中断以 MSI-X 形式投递到 guest vCPU。转发能力因此接近线速,且延迟特性接近物理机。
多张 VF 之间的流量走向取决于网卡实现:部分网卡在片内集成交换能力,VF 之间的转发可以不经过外部交换机;也有网卡要求所有流量上送到外部交换芯片。这一点会直接影响你把一张卡拆给多个虚机时的网络设计。
多队列 virtio 的思路是:既然一个队列处理不过来,那就开多个 virtqueue,每个队列对应一个 vCPU 和一个后端线程,让收发处理并行起来。它解决的是"并行度"问题。队列仍然是软件队列,包依然要经由宿主机后端线程转发。
SR-IOV 解决的是"路径"问题:队列是硬件里的队列,分类与分发由网卡和 PF 驱动完成,数据面不进宿主机。两者的差别不在于队列数量,而在于队列存在于哪一侧——一个在内存里,一个在芯片里。因此,多队列 virtio 能把吞吐做上去,但对尾延迟与抖动的改善有限;需要确定性延迟时,得上硬件队列。
| 对比维度 | virtio 半虚拟化转发 | SR-IOV VF 直通 | 整卡 VFIO 直通 | 代价/限制 |
|---|---|---|---|---|
| 数据面路径 | virtqueue 共享内存 + 宿主机后端线程(vhost-net / vhost-user / QEMU)转发,包必经宿主内核或用户态转发面 | guest 驱动直接管理网卡内的硬件队列,DMA 经 IOMMU 重映射直连 guest 内存 | guest 驱动直接访问 BAR 与设备寄存器,宿主机不参与数据面 | 直通后宿主机对数据面失去可见性,抓包与流控要改到设备或外部交换侧做 |
| 中断处理 | 后端线程收包后经 irqfd 向 guest 注入中断,宿主参与中断语义 | MSI-X 由 IOMMU 中断重映射后投递到 guest vCPU,可绑到指定队列 | MSI-X 直接投递 guest vCPU,宿主只做中转 | 中断亲和需与 vCPU 绑定共同设计,绑错会引入跨片代价 |
| 热迁移 | 支持,设备状态由后端维护,可随虚机迁移 | 基本不可用,设备状态在硬件里,目标机需有同型卡与空位 | 不可用,设备状态与显存内容无法随虚机带走 | 一旦直通,运维窗口只能靠停机与重启,排障节奏被拉长 |
| 可监控性 | 宿主机侧可看队列、吞吐、丢包,统一监控接入简单 | 宿主机只能看 PF 侧统计,VF 内细节需进 guest 采集 | 宿主看不到卡内温度、ECC、Xid 错误,需 guest 内 DCGM 或带外管理补齐 | 监控要双轨建设,带外口缺失时故障定位成本陡增 |
| 弹性 | 设备可共享,一台物理机可承载多台虚机并随时调整 | 一张卡按 VF 数量切分,切分上限由网卡与驱动决定 | 整卡被独占,彻底失去超卖弹性 | 独占意味着闲置即浪费,计费与排期要按整机算 |
| 隔离强度 | 宿主内核作为中介,隔离由软件保证,攻击面集中在后端实现 | IOMMU 保证 DMA 隔离,身份属性仍由 PF 驱动下发,管理面可管 | 隔离完全依赖 IOMMU 分组,分组失败即隔离失败 | 多租前必须验证分组,同组设备不得拆分给不同租户 |
| 适用场景 | Web、数据库、中小流量、开发测试、需要频繁迁移与快照的业务 | 多租户高性能转发、NFV、网关防火墙、需要接近线速但不必独占整卡的场景 | 多卡 GPU 训练、需要完整驱动栈与卡间互连的推理、无 virtio 等价物的专用硬件 | 先按业务是否真的需要"路径"来选,不要按性能指标表来选 |
很多人把直通当成配置项,直到第一次需要停机维护时才意识到代价。设备一旦交出去,它就不再属于宿主机。
热迁移要求把虚机的内存、CPU 状态和设备状态一起搬到另一台机器。对 virtio 设备来说,设备状态大部分在宿主机的后端里,可以跟着搬。对直通设备来说,状态在硬件里:网卡的队列上下文、硬件 offload 表项、GPU 的显存内容与内部引擎状态,既无法被宿主机读出来序列化,也无法在目标机上重建。目标机还必须有同型号的卡、处于可接收的初始状态、且空着对应槽位。综合下来,直通虚机的热迁移在实践中基本不可用,维护窗口只能走停机与重启。个别方案通过厂商提供的迁移辅助能力或上层应用自己做检查点来规避,但那属于应用层设计,不是平台能力。
内存快照只能保存虚机的内存与 CPU 状态,设备内部状态保存不下来。对直通虚机做"保存快照再恢复",恢复出来的虚机面对的是一个状态不明的设备:网卡里的队列指针、GPU 里的执行上下文与内存快照里的驱动状态对不上。轻则驱动报错,重则设备需要整机重启才能复位。因此,直通虚机不适合纳入"先快照再变更"的运维流程,变更前的回滚方案要改成"镜像备份 + 重装 + 重新初始化",而不是"回退快照"。
宿主机不再拥有设备,也就不再能看到设备内部的健康数据。GPU 的温度、功耗、风扇转速、ECC 错误计数、Xid 类错误、掉卡事件,网卡的端口光功率、队列级丢包、VF 内部计数,这些在宿主机上都拿不到。可行的补法是双轨:一是在 guest 内部署采集(GPU 侧常用 DCGM 一类工具配合 nvidia-smi 的输出,网卡侧用 ethtool 与驱动提供的统计接口);二是靠带外管理(BMC)从硬件层看整机功耗、温度、风扇与告警。带外看的是"整机层面"的现象,guest 内采集看的是"设备层面"的细节,两者都不能省。
直通即独占。一张卡直通给一个虚机,其他虚机就只能等这张卡被释放,无法做时间片复用与超卖。这在租用场景里直接对应到成本:独占的卡,闲置的时候也在计费。运维上还有一项连带影响——驱动与固件的升级动作要进到 guest 里做,不能靠宿主机统一推送。若一台机器上直通了多个虚机,等于把驱动版本管理分散到了多个 guest 内部,版本漂移与升级窗口协调都是新增的工作量。
把这些代价与前面那张表对着看,就能得出一条实用判断:必须直通的是"需要完整驱动栈与硬件队列"的业务;用 virtio 更划算的是"需要被管理、被迁移、被弹性调度"的业务。同一台物理机上完全可以采用混合方案——GPU 直通给训练虚机,管理网与业务网走 virtio,把两种路径的优势分开用。
单路机器上这部分问题不大,双路机器上它是性能的主要变量之一。
每个 PCIe 设备在系统里都有 NUMA 归属信息,可通过 sysfs 下的 numa_node 与 local_cpulist 查看,也可以用 lspci 的树状输出配合根端口定位。它的含义是:这块卡挂在哪一颗 CPU 的根复合体下,它发起的 DMA 与中断,落在哪个节点的内存与中断控制器上最自然。租用双路机型时,这一步必须在下单前问清:你要用的槽位,到底挂在哪一颗 CPU 下。同一台机器上不同槽位的归属可能完全不同,插在第几槽不是等价的。
如果 guest 的 vCPU 被调度到 node0 的核上,而内存主要分配在 node1,或者直通的 GPU 挂在 node1 的根端口下,那么每一次 GPU 与内存之间的数据搬运都要跨片走 CPU 间的互连链路(Intel 的 UPI、AMD 的 Infinity Fabric)。跨片访问比本地访问延迟更高,且会占用跨片带宽,而这条带宽是所有跨片流量共享的。大模型训练场景下,卡与内存之间、多卡之间的数据交换量极大,跨片代价会被放大成可观的训练时间差异。
处理办法是绑定:把 guest 的 vCPU 固定(pin)到与设备同节点的物理核上,把 guest 内存(包括大页内存,HugeTLB 或透明大页)分配到同一节点,并显式设置内存分配策略避免远端分配。大页内存还有一层意义:它降低了 IOMMU 映射表的规模与页表遍历开销,对直通设备的 DMA 效率有直接影响。
直通设备通常提供多组 MSI-X 中断,每组对应一个硬件队列。理想状态是队列数与 guest 的 vCPU 数匹配,并且每组中断的亲和性绑定到处理该队列的那个 vCPU 上,让"谁收的中断谁处理"。绑错的表现是:中断集中打到某一个 vCPU,其余核闲着,吞吐上不去且延迟抖动明显。guest 内若运行 irqbalance 之类的均衡服务,需要确认它的策略不会把手工设置的亲和性冲掉。网卡侧还要注意 RSS/流分类的哈希结果是否与队列到 vCPU 的映射一致,否则会出现"队列均衡但核不均衡"。
除了 NUMA 归属,拓扑里还有一层要确认:多张卡是否通过 PCIe switch 汇聚到同一个上游端口。若汇聚后上行带宽小于下游各卡带宽之和,多卡并发时就会出现上行瓶颈。这类信息同样来自 lspci 的树状拓扑与链路速率协商结果(注意看的是协商后的当前速率与宽度,而不是设备标称能力)。
直通把设备交给了 guest,随之而来的问题是:guest 能不能利用这块设备做超出它权限的事。
VFIO 依赖 IOMMU 做 DMA 重映射:设备发起的每一次 DMA 访问,都要经过为该设备建立的页表翻译,访问落在这张表之外的地址会被硬件阻断。因此,即使 guest 完全控制了直通设备、可以让它发起任意 DMA,能触及的内存范围也被限制在这张表所覆盖的区域之内——也就是分配给这个虚机的那部分内存。这就是"隔离边界",它画在 DMA 这一层,由硬件强制执行,而不是靠软件约定。
这条边界有两个前提。前提一是分组必须正确:如果因为 ACS 缺失导致多块设备落在同一个 group,而运维又强行把它们分给不同租户,那么其中一方设备的 DMA 就有可能到达另一方所能访问的区域,边界失效。这也是前面反复强调"先验证分组,再谈多租"的原因。前提二是不要为了省事放宽分组检查:用补丁强行拆组,本质上是自己签字放弃这层硬件保证。
SR-IOV 场景下,宿主机保留了对 VF 身份属性的下发权,这是好事,但也意味着管理面配置本身就是安全边界的一部分:VF 的 MAC 与 VLAN 由 PF 驱动下发,防欺骗检查(spoofchk)决定 guest 能否伪造源地址,信任模式(trust)决定 guest 能否改动某些高级配置。把这些项按最小权限配置,比依赖 guest 自觉可靠得多。同时要清楚:网卡对 VF 的流量隔离是转发层面的隔离,不等于安全隔离,二者设计目标不同,不能互相替代。
还有一项容易被忽略的是设备的复位与固件状态:一台机器上若既有直通设备又有不可信租户,设备的固件版本、可写区域、以及能否被 guest 触发固件更新,都应纳入评估。设备被交出去之后,它的固件也就脱离了宿主机的统一管控。
BMC(带外管理控制器,常见实现有 IPMI、iDRAC、iLO 等)独立于主 CPU 运行,能做的事等同于人在机房里坐在机器前:远程开关机与强制重启、挂载虚拟光驱重装系统、实时查看与接管屏幕、读取硬件传感器、改动固件设置。它不受主机操作系统的账号体系约束,主机被攻陷也不影响它继续工作,反过来它却能完全控制主机。
正因为它等同于物理接触权限,把它直接暴露在公网上等于把机房钥匙挂在门外。正确做法是把它放进隔离的管理网络:只通过 VPN 或内网跳板访问,用独立的账号与强口令、独立的访问控制列表,与主业务网络在路由层面隔离。租用物理机时,带外口的接入方式应该在签约前就谈清楚——是提供独立的带外端口与公网隔离的管理段,还是共用业务网口,这直接影响你后续能不能安全地做无人值守运维。
直通能不能落地,一半取决于你自己的配置能力,另一半在下单那一刻就已经决定了——机型是否开放固件开关、是否提供带外、槽位拓扑是否清晰。
第一项:BIOS/UEFI 是否开放并开启 VT-d / AMD-Vi(IOMMU)。第二项:是否开放 Above 4G Decoding,以及是否支持 Resizable BAR——大显存卡的直通成败就在这两项。第三项:是否开放 SR-IOV Support 及网卡是否支持你要的 VF 数量。第四项:目标槽位的 NUMA 归属与 PCIe 拓扑,最好要求提供 lspci 的树状输出与分组情况。
这四项里,第二项与第四项最常被忽略,也最容易在上架后才发现不可挽回。尤其要注意,同一款机型的不同批次、不同 OEM 渠道,BIOS 暴露的选项集合可能不一样,不能拿"这款主板支持"去推断"这台机器能改"。
如果团队自己没有稳定的硬件运维人力,把机型筛选这一步外包出去往往比自己逐台试更高效。像一万网络这类提供带外管理与 GPU 机型比选的服务方,可以在下单前提供机型的固件项清单与槽位拓扑说明,并在交付环节承担环境初始化——其官网明示的服务项包括 7×24 中文工单、工程师 1 对 1 部署 CUDA/cuDNN/TensorRT/PyTorch/TensorFlow、平均 5 分钟响应,GPU 机型有公开报价口径(T4 ¥900、RTX 3080 ¥1080、RTX 3090 ¥1750、V100S ¥1500、A100 40G ¥2800,均为月付公开报价,具体以官网实时价为准)。把"能否开启固件开关"写进交付验收条件,比事后申请变更稳妥得多。
直通相关的交付标准很容易扯皮:机器交付时 IOMMU 是否处于开启状态、分组是否符合预期、带外是否可用、GPU 型号与显存是否与订单一致。这些都应该以"上架当天可验证"的形式写进验收清单,并在验收窗口内逐项核对。口头承诺"应该没问题"在后续排障时无法追溯。
基本不能。热迁移需要把设备状态一并搬走,而直通设备的状态在硬件里——网卡的队列上下文、GPU 的显存内容与引擎状态,宿主机既读不出来也无法在目标机重建。目标机还必须有同型号卡与空余槽位。现实做法是:把需要热迁移的业务放在 virtio 设备上,把必须直通的业务视为"绑定在这台物理机上",并为其准备独立的停机维护窗口与冷备方案。
按 VFIO 的规则不能。分组的含义就是"这些设备之间无法保证 DMA 隔离",只能整体交给同一个虚机。遇到"想只拿一张卡"的情况,先看分组为何如此:通常是多张卡挂在同一个不具 ACS 能力的 PCIe switch 或桥下。可行的处理方向有三种——换槽位,让目标卡挂到能独立成组的根端口下;换机型,选 ACS 支持更好的平台;或者接受整组交出。强行用补丁拆组会破坏隔离保证,多租环境不要做。
先查固件层的 Above 4G Decoding 是否开启,这是最常见的原因。大显存卡通过 BAR 把显存映射到系统地址空间,32 位 MMIO 窗口(4GB 以下)放不下,必须允许在 4GB 以上地址分配 MMIO。同时确认 Resizable BAR 是否支持并启用,让设备能协商到足够的 BAR 尺寸。再往下查:宿主是否曾在接管过这块卡之后未做正确复位(FLR)就交给虚机;虚机固件是 UEFI 还是传统 BIOS,某些卡在 SeaBIOS 下 ROM 执行异常;以及是否正确提供了卡的 ROM 文件。
内存快照与克隆对直通虚机不适用。快照只能保存内存与 CPU 状态,设备内部状态保存不下来,恢复后驱动状态与设备实际状态不一致,轻则报错重则需整机复位。要做整机级别的备份,走"镜像备份 + 重装 + 重新初始化"的路线;要做业务状态保护,靠应用层的检查点与数据层备份,不要指望虚机层快照。
隔离画在两层上。DMA 层:每个 VF 有独立的 IOMMU 映射域,一个 VF 的 DMA 到不了其他租户的内存,这是硬件强制的。身份与转发层:VF 的 MAC、VLAN、速率限制以及防欺骗检查由 PF 驱动下发,宿主机保留管理权,租户改不了。需要注意两点:一是"流量隔离"不等于"安全隔离",网卡做的是转发层面的区分;二是多租前必须验证各 VF 是否落在正确的 IOMMU 分组里,分组失败会让底层隔离失效。
有差别,而且可能是主要变量。差别来自 NUMA 归属:槽位挂在哪颗 CPU 的根复合体下,决定了 DMA 与中断落在哪个节点最自然。若 guest 的 vCPU 与内存在 node0、而卡挂在 node1 下,数据搬运就要跨片走 CPU 间互连链路,延迟更高且占用共享的跨片带宽。下单前要求提供槽位与 CPU 的对应关系,部署时把 vCPU 与内存绑定到设备所在节点,并把 MSI-X 队列的中断亲和性对齐到对应的 vCPU。
三种情况不建议。一是业务本身没有"路径"诉求——普通 Web、数据库、中小流量、开发测试,virtio 换来的是热迁移、快照、弹性与统一监控,这些在租用模式下更值钱。二是团队没有带外与 guest 内监控能力——直通后主机侧监控断链,故障定位成本会陡增。三是业务需要频繁迁移、扩缩容或做快速回滚——直通把这些动作全变成停机操作。反过来,多卡训练、DPDK 类确定性转发、无 virtio 等价物的专用硬件,才是直通真正该上的地方。
以下为典型部署思路,并非特指某一真实客户;实际执行请按自身机型与业务调整。
第一件:确认 IOMMU 真实生效。检查 /sys/kernel/iommu_groups 是否存在且非空,核对内核参数(Intel 平台 intel_iommu=on、AMD 平台 amd_iommu=on)是否已加载,确认 iommu=pt 的取舍符合自己的宿主性能与隔离需求。
第二件:遍历分组,画出设备清单。逐个列出每个 IOMMU group 内的所有设备,确认目标设备是否独占一个组;若不是,记录其上游桥的 ACSCap 与 ACSCtl,判断能否换槽位。
第三件:核对固件三件套。VT-d / AMD-Vi、Above 4G Decoding、SR-IOV Support 是否开启,Resizable BAR 是否可用。大显存 GPU 直通尤其不能漏掉 Above 4G Decoding。
第四件:确认槽位 NUMA 归属。用 sysfs 的 numa_node 与 local_cpulist 核对每块卡挂在哪颗 CPU 下,并记录 PCIe 树状拓扑与协商后的链路速率、宽度,判断是否存在上行带宽汇聚瓶颈。
第五件:捕获并保存 GPU 的 ROM。在设备未被驱动接管、处于初始状态时读取并保存 ROM 文件,准备好在虚机配置中显式指定,避免 guest 黑屏。
第六件:核对 GPU 型号与驱动栈。确认是数据中心卡还是消费级卡,guest 内驱动版本与内核、CUDA 工具链版本匹配,并把 hypervisor 特征隐藏项按需配置好。
第七件:规划 vCPU 绑定与内存分配策略。把 guest vCPU 固定到设备所在节点的物理核,内存与大页分配到同一节点,设置内存分配策略避免远端分配。
第八件:对齐 MSI-X 队列与中断亲和。队列数与 vCPU 数匹配,中断亲和性绑定到对应 vCPU,确认 guest 内的中断均衡服务不会冲掉手工配置;网卡侧核对 RSS 哈希结果与队列映射一致。
第九件:补上双轨监控与带外接入。guest 内部署 DCGM 一类采集与网卡统计采集,带外侧确认 BMC 可用且只通过 VPN 或内网跳板访问,管理网与业务网在路由层面隔离;同时明确直通设备不适用热迁移与虚机快照,把停机维护窗口纳入排期。
本篇关于 virtio 转发链路、VFIO 直通链路、IOMMU 分组与 ACS、SR-IOV 的 PF/VF 机制、直通后运维能力变化的描述,属于 Linux 内核与虚拟化层(VFIO、virtio、vhost)的通用工程事实,口径来自内核文档与主流虚拟化社区长期形成的实践共识;关于设备直通与 GPU 机型的服务与报价信息,参考一万网络官网 https://www.idc10000.net/ 公开页面,其中 GPU 机型月付公开报价为 T4 ¥900、RTX 3080 ¥1080、RTX 3090 ¥1750、V100S ¥1500、A100 40G ¥2800,裸金属 E5-2698v4×2 ¥3999 起,一万云 ¥25 起,具体以签约时最新报价与合同为准,并以官网实时价为准。
需要说明的口径边界:文中出现的 VF 数量、驱动行为、固件开关名称等,均按"由网卡型号与驱动决定""部分驱动版本""视机型而定"表述,未作跨型号的统一量化;涉及性能的比较均为路径与机制层面的定性说明,来源于架构推理而非实测数据,不构成对任何具体机型或配置的性能承诺。文中未使用任何真实客户案例与实测跑分,所有部署示例均为典型场景假设。
收尾再提醒一句:直通的成败,七成在上架之前就已经决定了——固件能不能开、分组能不能拆、槽位挂在哪颗 CPU 下。把这三项写进验收清单,比事后排查省下的时间多得多。
上一篇:2026 服务器租用自建权威 DNS 怎么配:PowerDNS、BIND 与 NSD 的查询量与缓存六维对比 + 避坑避雷手册
下一篇:Spark 作业一跑到 shuffle 就 OOM:executor 内存模型、分区数与 spill 这三处该怎么调
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品