KVM虚拟化:(十二)半虚拟化驱动

admin 2023年04月24日 742次浏览

QEMU/KVM 提供了全虚拟化环境,可以让客户机不经过任何修改就能运行在 KVM 环境中。不过,KVM 在 I/O 虚拟化方面,传统的方式是使用 QEMU 纯软件的方式来模拟 I/O 设备,其效率并不太高。在 KVM 中,可以在客户机中使用半虚拟化驱动来提高客户机的性能,尤其是 I/O 性能。目前 KVM 中实现半虚拟化驱动的方式是采用 virtio 这个 Linux 上的设备驱动标准框架

1、QEMU模拟I/O设备

1.1、优点

可以通过软件模拟出各种各样的硬件设备,包括一些不常用的或很老很经典的设备,而且该方式不用修改客户机操作系统,就可以使模拟设备在客户机中正常工作。在 KVM 客户机中使用这种方式,对于解决手上没有足够设备的软件开发及调试有非常大的好处

1.2、缺点

每次 I/O操作的路径比较长,有较多的 VMEntry、VMExit 发生,需要多次上下文切换,以及多次数据复制,所以它的性能较差

2、virtio

2.1、基本原理

virtio 分为前端驱动和后端处理程序,前端驱动是在客户机中存在的驱动程序模块,而后端处理程序是在 QEMU 中实现的。在前后端驱动之间,还定义了两层来支持客户机与 QEMU 之间的通信。其中,virtio 层是虚拟队列接口,它将前端驱动程序附加到后端处理程序,而 virtio-ring 实现了环形缓冲区,用于保存前端驱动和后端处理程序执行的信息。该环形缓冲区可以一次性保存前端驱动的多次 I/O 请求,并且交由后端驱动去批量处理,最后实际调用宿主机中设备驱动实现物理上的 I/O 操作,这样做就可以根据约定实现批量处理而不是客户机中每次 I/O 请求都需要处理一次,从而提高客户机与 Hypervisor 信息交换的效率

2.2、优点

virtio 半虚拟化驱动的方式,可以获得很好的 I/O 性能,其性能几乎可以达到与 非虚拟化环境中的原生系统差不多的 I/O 性能。所以,在使用 KVM 之时,如果宿主机内核和客户机都支持 virtio,一般推荐使 virtio,以达到更好的性能

2.3、缺点

virtio 要求客户机必须安装特定的 virtio 驱动使其知道是运行在虚拟化环境中,并且按照 virtio 的规定格式进行数据传输。客户机中可能有一些老的 Linux 系统不支持 virtio,还有一些主流的 Windows 系统需要安装特定的驱动才支持 virtio

2.4、安装virtio驱动

宿主机中 Linux2.6.24 及以上的 Linux 内核版本都支持 virtio 。由于 virtio 的后端处理程序是在位于用户空间的 QEMU 中实现的,所以,在宿主机中只需要比较新的内核即可,不需要特别地编译与 virtio 相关的驱动

客户机需要有特定的 virtio 驱动的支持,以便客户机能识别和使用 QEMU 模拟的 virtio 设备

2.4.1、在Linux中安装

较新版本的 Linux 系统中都默认自动安装有 virtio 相关的半虚拟化驱动。可以使用 grep -i virtio /boot/config-$(uname -r) 命令查看内核的配置文件来确定某发行版是否支持 virtio 驱动,与之相关的配置有以下几项

CONFIG_VIRTIO=m
CONFIG_VIRTIO_PCI=m
CONFIG_VIRTIO_BALLOON=m
CONFIG_VIRTIO_BLK=m
CONFIG_SCSI_VIRTIO=m
CONFIG_VIRTIO_NET=m
CONFIG_VIRTIO_CONSOLE=m
CONFIG_HW_RANDOM_VIRTIO=m
  • 查看宿主机模块支持情况

    此处以 rockyLinux9 为例查看配置项情况

    [root@kvm ~]# grep -i virtio /boot/config-$(uname -r)
    CONFIG_BLK_MQ_VIRTIO=y
    CONFIG_VIRTIO_VSOCKETS=m
    CONFIG_VIRTIO_VSOCKETS_COMMON=m
    CONFIG_VIRTIO_BLK=m
    CONFIG_SCSI_VIRTIO=m
    CONFIG_VIRTIO_NET=m
    CONFIG_VIRTIO_CONSOLE=m
    CONFIG_HW_RANDOM_VIRTIO=y
    CONFIG_DRM_VIRTIO_GPU=m
    CONFIG_SND_VIRTIO=m
    CONFIG_ARCH_HAS_RESTRICTED_VIRTIO_MEMORY_ACCESS=y
    CONFIG_VIRTIO_PCI_LIB=y
    CONFIG_VIRTIO_MENU=y
    CONFIG_VIRTIO_PCI=y
    CONFIG_VIRTIO_PCI_LEGACY=y
    CONFIG_VIRTIO_VDPA=m
    CONFIG_VIRTIO_BALLOON=m
    CONFIG_VIRTIO_MEM=m
    CONFIG_VIRTIO_INPUT=m
    CONFIG_VIRTIO_DMA_SHARED_BUFFER=m
    CONFIG_VIRTIO_IOMMU=y
    CONFIG_VIRTIO_FS=m
    
  • 查看客户机virtio模块加载情况

    [root@localhost ~]# lsmod | grep virtio
    virtio_gpu             77824  0
    virtio_dma_buf         16384  1 virtio_gpu
    drm_shmem_helper       20480  1 virtio_gpu
    drm_kms_helper        200704  3 virtio_gpu
    virtio_balloon         24576  0
    drm                   622592  4 drm_kms_helper,drm_shmem_helper,virtio_gpu
    virtio_net             65536  0
    virtio_blk             20480  3
    virtio_console         40960  1
    net_failover           24576  1 virtio_net
    

2.4.2、Windows客户端安装

如果需要在 Windows 中使用 virtio 驱动,可以通过 Linux 系统发行版自带软件包安装,也可以到网上下载 Windows virtio 驱动自行安装

  • 通过官方的RPM获得

    [root@kvm ~]# yum install virtio-win -y
    

    安装完以后,在 /usr/share/virtio-win 目录下可以看到 virtio-win-xxx.iso 文件,其中包含了所需要的驱动程序

    [root@kvm ~]# ls -lah /usr/share/virtio-win
    总用量 524M
    drwxr-xr-x    7 root root  185  4月  8 21:38 .
    drwxr-xr-x. 215 root root 8.0K  4月  8 21:38 ..
    -rw-r--r--    1 root root  465  1月 24 01:49 agents.json
    drwxr-xr-x    6 root root   61  4月  8 21:38 drivers
    drwxr-xr-x    2 root root   56  4月  8 21:38 guest-agent
    -rw-r--r--    1 root root  40K  1月 24 01:49 info.json
    drwxr-xr-x    2 root root   98  4月  8 21:38 installer
    drwxr-xr-x    2 root root   58  4月  8 21:38 qxl-wddm-dod
    drwxr-xr-x    2 root root   64  4月  8 21:38 spice-vdagent
    -rw-r--r--    1 root root 524M  1月 24 01:49 virtio-win-1.9.32.iso
    
  • Windows安装包下载

  • 然后将iso文件挂载到客户机上,进行驱动安装即可

3、virtio_balloon

3.1、ballooning简介

要改变客户机的内存大小,通常要先关闭客户机,修改启动时的内存配置,然后重启客户机才能实现。而内存的 ballooning 技术可以在客户机运行时动态地调整它所占用的宿主机内存资源,而不需要关闭客户机

当宿主机的内存不足时,可以请求将分配给客户机的内存空间回收一部分,客户机就会释放一部分空闲的内存给宿主机使用(但不能给其他客户机使用);反之,当客户机中内存不足时,也可以让宿主机分配一部分内存给客户机使用

3.2、KVM中ballooning工作流程及优劣势

3.2.1、工作流程

  • Hypervisor(KVM) 发送请求到客户机操作系统,让其归还一定数量的内存给 Hypervisor

  • 客户机操作系统中的 virtio_balloon 驱动接收到 Hypervisor 的请求

  • virtio_balloon 驱动使客户机的内存气球膨胀,气球中的内存就不能被客户机访问。如果此时客户机中内存剩余量不多,并且不能让内存气球膨胀到足够大以满足 Hypervisor 的请求,那么virtio_balloon 驱动也会尽可能多地提供内存使气球膨胀,尽量去满足 Hypervisor 所请求的内存数量

  • 客户机操作系统归还气球中的内存给 Hypervisor

  • Hypervisor 可以将从气球中得来的内存分配到任何需要的地方

  • 如果从气球中得到的内存没有处于使用中,Hypervisor 也可以将内存返还给客户机

3.2.1、优势

  • 因为 ballooning 能够被控制和监控,所以能够潜在地节约大量的内存

  • ballooning 对内存的调节很灵活,既可以精细地请求少量内存,也可以粗犷地请求大量的内存

  • Hypervisor 使用 ballooning 让客户机归还部分内存,从而缓解其内存压力

3.2.2、劣势

  • ballooning 需要客户机操作系统加载 virtio_balloon 驱动,然而并非每个客户机系统都有该驱动

  • 如果有大量内存需要从客户机系统中回收,那么 ballooning 可能会降低客户机操作系统运行的性能

  • 目前没有比较方便的、自动化的机制来管理 ballooning,一般都采用在 QEMU monitor 中执行balloon 命令来实现 ballooning

  • 内存的动态增加或减少可能会使内存被过度碎片化,从而降低内存使用时的性能

3.3、ballooning使用示例

3.3.1、在KVM中使用

在 qemu 命令行中可用 -balloon virtio 参数来分配 balloon 设备给客户机,使其调用 virtio_balloon 驱动来工作,而默认值为没有分配 balloon 设备

在 QEMU monitor 中,分别使用 info balloon balloon numMB两个命令用于查看和设置客户机内存的大小

  • QEMU 启动客户机时分配 balloon 设备

    [root@kvm oldyan]# qemu-system-x86_64 -enable-kvm /data/vmhost/rocky9.qcow2 -smp 4 -m 8G -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4
    
  • 在客户机中查看balloon设备及内存使用情况

    [root@vm-rocky9 ~]# lsmod | grep -i balloon
    virtio_balloon         24576  0
    [root@vm-rocky9 ~]# lspci | grep -i balloon
    05:00.0 Unclassified device [00ff]: Red Hat, Inc. Virtio memory balloon (rev 01)
    
    [root@vm-rocky9 ~]# free -h
                   total        used        free      shared  buff/cache   available
    Mem:           7.3Gi       762Mi       6.3Gi        35Mi       549Mi       6.6Gi
    

3.3.2、在线调整内存

在实际环境中,客户机系统的资源的平均使用率一般并不高,通常是一段时间负载较重,一段时间负载较轻。可以在一个物理宿主机上启动多个客户机,通过 ballooning 的支持,在某些客户机负载较轻时减少其内存使用,将内存分配给此时负载较重的客户机

3.3.2.1、在Linux中实现内存动态调整

在 libvirt 工具的 virsh 管理程序中,可以使用 setmem 命令动态更改客户机的可用内存容量

  • 语法

     setmem <domain> --size <size> [--config] [--live] [--current]
    

    –domain <字符串> 域名、id 或 uuid
    –size <数字> 新内存大小,以整数计(默认为 KiB)
    –config 影响下一次引导
    –live 影响运行的域
    –current 影响当前域

  • 示例

    # 调整内存前
    [root@vm-rocky9 ~]# free -h
                   total        used        free      shared  buff/cache   available
    Mem:           7.3Gi       684Mi       6.4Gi        35Mi       490Mi       6.6Gi
    Swap:          4.0Gi          0B       4.0Gi
    
    # 执行内存减小
    [root@kvm ~]# virsh setmem --domain rocky9 --size 2097152 --current
    
    # 查看客户机内存
    [root@vm-rocky9 ~]# free -h
                   total        used        free      shared  buff/cache   available
    Mem:           1.5Gi       451Mi       1.1Gi        18Mi       130Mi       1.1Gi
    Swap:          4.0Gi       194Mi       3.8Gi
    
    # 增加客户机内存
    [root@kvm ~]# virsh setmem --domain rocky9 --size 4GB --current
    
    # 查看客户机内存
    [root@vm-rocky9 ~]# free -h
                   total        used        free      shared  buff/cache   available
    Mem:           3.2Gi       434Mi       2.9Gi        18Mi        96Mi       2.8Gi
    Swap:          4.0Gi       194Mi       3.8Gi
    
3.3.2.1、在Windows中实现内存动态调整

在安装了 virtio 驱动的 Windows 客户机中,同样可以实现内存的动态调整,但是如果是减小内存,在系统中看到的总内存不会减小,而是通过压缩内存来实现;最大使用内存不能超过客户机的最大分配内存

  • 示例: 将内存降低到4GB

4、virtio_net

在选择 KVM 中的网络设备时,一般来说应优先选择半虚拟化的网络设备,而不是纯软件模拟的设备。使用 virtio_net 半虚拟化驱动可以提高网络吞吐量和降低网络延迟,从而让客户机中网络达到几乎和非虚拟化系统中使用原生网卡的网络差不多的性能

4.1、检查QEMU是否支持virtio类型的网卡

[root@kvm ~]# qemu-system-x86_64 -net nic,model=?
Supported NIC models:
e1000、e1000-82544gc、e1000-82545em、e1000e、i82550、i82551、i82557a、i82557b、i82557c
i82558a、i82558b、i82559a、i82559b、i82559c、i82559er、i82562、i82801、ne2k_pci、pcnet
rtl8139、tulip、virtio-net-pci、virtio-net-pci-non-transitional、virtio-net-pci-transitional、vmxnet3

4.2、给客户机分配virtio网卡设备

在使用 virt-manager 创建虚拟机时,在选择 “网卡型号” 时,直接选择 “virtio” 即可