KVM学习笔记(性能优化)

1 NUMA

NUMA(Non Uniform Memory Access Architecture)用来解决多 CPU 系统下共享 BUS 带来的性能瓶颈问题。
所有的CPU 通过一个 BUS 和 RAM 相连,BUS 会成为性能的杀手。而且,加的 CPU 越多,性能损耗会越高。

多CPU通过一个BUS访问RAM的场景

这时候 NUMA 架构就展露身手了:通过把 CPU 和临近的 RAM 当做一个 node,CPU 会优先访问距离近的 RAM,速度较快。同时,CPU 直接有一个快速通道连接,所以 每个CPU 还是访问到所有的 RAM 位置,只是访问其他CPU下的内存速度相对较慢。
NUMA示意图

KVM有自动化的NUMA平衡功能,虚拟机会感知物理机的NUMA架构,自动的尽可能将虚机CPU和内存分配在一个NUMA node内。

2 内存气球

虚拟机分配的总内存一定,内存气球在虚拟机中,气球中的内存是可以给除虚拟机以外的其他资源使用的,通过调节气球的大小可以动态的调节虚拟机实际使用的内存。
当虚拟机内存空闲时,内存气球充气,有更多的内存可以分配给其他资源。
当虚拟机内存紧张时,内存气球放气,内存更多的分配给虚拟机。


内存气球示意图

3 内存共享

类似磁盘的链接克隆,当多台虚拟机内存中有一部分时相同的(如虚拟机使用相同的操作系统),则在物理内存中将这部分内存做只读处理,虚拟机不再进行重复的内存分配而是通过指针指向这部分共享的物理内存,在需要进行内存写入时进行复制。


内存共享示意图

4 磁盘IO控制

磁盘IO控制可以避免某个虚拟机过度使用主机资源,有两种方式:

  • 设置磁盘权重:在整体中的权重,数值范围100-1000
  • 限制具体IO

通过virsh blkiotune实现,或修改虚拟机配置文件

#设置虚拟机IO权重
virsh blkiotune  
    --weight   IO Weight
    --device-weights   per-device IO Weights, in the form of /path/to/device,weight,...
    --device-read-iops-sec   per-device read I/O limit per second, in the form of /path/to/device,read_iops_sec,...
    --device-write-iops-sec   per-device write I/O limit per second, in the form of /path/to/device,write_iops_sec,...
    --device-read-bytes-sec   per-device bytes read per second, in the form of /path/to/device,read_bytes_sec,...
    --device-write-bytes-sec   per-device bytes wrote per second, in the form of /path/to/device,write_bytes_sec,...
    --config         affect next boot
    --live           affect running domain
    --current        affect current domain
#virsh blkiotune Centos6 --weight 500 --live

#设置虚拟机磁盘具体IO
virsh blkdeviotune   
    --total-bytes-sec   total throughput limit, as scaled integer (default bytes)
    --read-bytes-sec   read throughput limit, as scaled integer (default bytes)
    --write-bytes-sec   write throughput limit, as scaled integer (default bytes)
    --total-iops-sec   total I/O operations limit per second
    --read-iops-sec   read I/O operations limit per second
    --write-iops-sec   write I/O operations limit per second
    --total-bytes-sec-max   total max, as scaled integer (default bytes)
    --read-bytes-sec-max   read max, as scaled integer (default bytes)
    --write-bytes-sec-max   write max, as scaled integer (default bytes)
    --total-iops-sec-max   total I/O operations max
    --read-iops-sec-max   read I/O operations max
    --write-iops-sec-max   write I/O operations max
    --size-iops-sec   I/O size in bytes
    --group-name   group name to share I/O quota between multiple drives
    --total-bytes-sec-max-length   duration in seconds to allow total max bytes
    --read-bytes-sec-max-length   duration in seconds to allow read max bytes
    --write-bytes-sec-max-length   duration in seconds to allow write max bytes
    --total-iops-sec-max-length   duration in seconds to allow total I/O operations max
    --read-iops-sec-max-length   duration in seconds to allow read I/O operations max
    --write-iops-sec-max-length   duration in seconds to allow write I/O operations max
    --config         affect next boot
    --live           affect running domain
    --current        affect current domain
#virsh blkdeviotune Centos6 vda --total-bytes-sec 10240

5 virt-manager中的性能管理

  1. 尽可能的提供客户虚拟机详细信息,以便Hypervisor根据操作系统类型提供特定的优化功能。
  2. 删除不使用的设备节省Host的资源,如:声卡,光驱

6 网络性能优化

常规建议

  1. 业务、心跳、存储、备份网络分离,避免使用单一网络造成过载。
  2. 调整MTU,减少报文的分片
  3. 使用arp_filter阻止arp flux问题:
    运行echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter

arp flux问题

当Linux主机有两个网卡连接到一个子网时,收到任意一个网卡IP地址的ARP请求,都会同时将两张网卡的 MAC 地址作为响应,且响应返回时先后顺序固定(返回 ARP 响应的先后顺序和路由表中两条本地子网路由的顺序有关,而这两条路由的顺序又和两张网卡的启动顺序有关)。Linux认为IP 地址属于内核,而不属于接口,arp_filter 定义了内核是否可以使用其他网卡上的地址进行 ARP 响应。

arp flux示意图

virtio和vhost

不使用virtio时IO路径为Guest->kernel->IO环->qemu->tap->nic
使用virtio时IO路径为Guest->IO环->qemu->tap->nic
使用vhost时virtio网络后端移到内核中,更加高效。


全模拟IO路径

virtio和vhost

网卡直通和SR-IOV

当虚拟机对网络IO要求很高时,可以将物理网卡直通给虚拟机使用,利用interl的VT-d、AMD的AMD-Vi技术。
优点:IO性能好。
缺点:因为虚拟机绑定物理设备,无法热迁移,物理设备无法复用给其他虚拟机。

SR-IOV(Single Root-IO Virtualization),需要特殊的支持此特性的网卡,此种网卡可以虚拟出多个虚拟网卡,这种虚拟化在硬件中实现,不占用宿主机的资源,在Linux内核中来看就是多个不同PCI-E的网卡,从而将不同的虚拟网卡直通给虚拟机使用。


网卡直通和SR-IOV

桥接零复制传输 Bridge Zero Copy Transmit

对于大尺寸的数据包较为有效。通常在客机网络和外部网络间的大数据包传输中,它对主机 CPU 负荷的减少可达到 15%,对吞吐量没有影响。
它不对客机到客机、客机到主机或小数据包负载造成影响。
Red Hat Enterprise Linux 7 虚拟机完全支持桥接零复制传输,但是被默认禁用。

由于在之前版本中出现过利用桥接零复制传输的攻击,所以此功能默认被禁用了

开启桥接零复制传输功能

#创建新文件vhost-net.conf
vim /etc/modprobe.d/vhost-net.conf
#添加如下内容
options vhost_net experimental_zcopytx=1

#如果想再次禁用
modprobe -r vhost_net
modprobe vhost_net experimental_zcopytx=0

多队列的virtio-net

当网卡驱动加载时,通过获取的网卡型号,得到网卡的硬件queue的数量,并结合CPU核的数量,最终通过Sum=Min(网卡queue,CPU core)得出所要激活的网卡queue数量(Sum),并申请Sum个中断号,分配给激活的各个queue,这样可以利用多核CPU分别中断处理多个网卡queue,从而提高网络IO性能。
修改虚拟机配置文件,调整虚拟机网卡支持的多队列数,与虚拟CPU数相同,本例以2核CPU为例

#修改虚拟机配置文件interface字段
    
      
      
      
        #添加这行,N是虚拟CPU数,本例填2
    ...
    

查看网卡支持的队列数,以2核CPU为例

[root@localhost ~]$ ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             0
TX:             0
Other:          0
Combined:       2
Current hardware settings:
RX:             0
TX:             0
Other:          0
Combined:       1
#2代表 combined可以设置的最大值是2,1代表当前的队列设置是1

运行ethtool -L eth0 combined 2开启网卡多队列功能

[root@localhost ~]$ ethtool -L 2 eth0
[root@localhost ~]$ ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             0
TX:             0
Other:          0
Combined:       2
Current hardware settings:
RX:             0
TX:             0
Other:          0
Combined:       2

7 存储性能优化

磁盘IO节流

限制虚拟机iops和吞吐量,例如,将虚拟机中的vda节流至I/O每秒1000、吞吐量为每秒50MB:

virsh blkdeviotune Centos6 vda --total-iops-sec 1000 \
--total-bytes-sec 52428800

缓存

kvm中host和guest各自维护自己的page caches,使得内存中有两份缓存数据。host的缓存为page cache可以理解为读缓存,guest的缓存为disk write cache,可以理解为写缓存,前者优化读性能,后者优化写性能。如果disk write cache开启,那么一旦数据存在disk write cache中,写操作认为已经完成,即使真正的数据尚未在物理磁盘上。因此如果掉电,则存在数据丢失风险,数据完整性得不到保障。除非用户手动指定fsync(同步内存中所有已修改的文件数据到储存设备),或者disk wriet cache中的内容发生了变化,才会把数据写到物理磁盘上。

注释:

O_DIRECT - 绕过缓冲区高速缓存 - 直接IO:Linux允许应用程序在执行磁盘IO时绕过缓冲区高速缓存,从用户空间直接将数据传递到文件或磁盘设备,称为直接IO(direct IO)或者裸IO(raw IO)

缓存选项:

none

  • I/O from the guest is not cached on the host, but may be kept in a writeback disk cache. Use this option for guests with large I/O requirements.(guest 使用 writeback, host 不使用 page cache,相当于 guest 直接访问主机磁盘。)
    这种模式下虚拟机磁盘镜像文件或者块设备会使用 O_DIRECT 语义, 则 host 的 page cache 被绕过, I/O 直接在 qemu-kvm 的用户空间 buffers 和 host 的存储设备间发生。因为实际存储设备可能在写数据放到写队列后就上报写完成,虚拟机上的存储控制器被告知有回写缓存(writeback cache), 所以 guest 需要下发刷盘(flush)命令来保证数据一致(落盘)。相当于直接访问 host 磁盘,性能不错。
    在虚拟机中使用此选项来满足大多数需求,是支持迁移的最佳和唯一选项。

writethrough

  • I/O from the guest is cached on the host but written through to the physical medium. This mode is slower and prone to scaling problems. Best used for small number of guests with lower I/O requirements. Suggested for guests that do not support a writeback cache (such as Red Hat Enterprise Linux 5.5 and earlier), where migration is not needed.
    数据完整性得到保障(不经过写缓存,而是直接写到物理磁盘),读操作性能较好,写操作性能较差。

writeback

  • I/O from the guest is cached on the host.
    Both the host page cache and the disk write cache are enabled,读写操作性能都很优异,唯一的缺点就是写操作的数据掉电可能丢失,无法保证数据完整性。qemu-kvm1.2版本以上为默认缓存模式。

directsync

  • Similar to writethrough, but I/O from the guest bypasses the host page cache.
    两种缓存均关闭,读写操作性能较差。

unsafe

  • The host may cache all disk I/O, and sync requests from guest are ignored.
    guest发出的刷新缓存指令被忽视,意味着以牺牲数据的完整性来换取性能的提升。

default

  • If no cache mode is specified, the system's default settings are chosen.


    缓存选项

IO模式

Linux系统上异步IO常见的有两种实现,一种是kernel native AIO,另外一种是threaded aio: user space AIO emulated by posix thread workers。
Kernel native AIO : Kernel的原生态异步IO实现。
Threaded AIO : Linux用户空间异步IO的实现,其实它不是真正的异步IO,是通过启动一定数量的blocking IO线程来模拟异步IO。这种实现有不少缺点,毕竟有不少线程开销,还在改进中。默认是Thread模式

IO选项

多队列virtio-scsi

使每个虚拟CPU可以使用独立队列和中断,从而不会影响到其他虚拟CPU。
RHEL/CentOS7 默认禁用多队列virtio-scsi。
启动方法:

#在XML配置文件中添加如下命令,其中N为虚拟机CPU队列的总数

      
 

8 内存及CPU优化

8.1 使用virsh调整内存配置

XML文件中的元素用于配置虚拟机内存设置。
如果没有,则使用默认配置。
也可通过virsh memtune命令来进行配置

#设置虚拟机内存配额
memtune 
  OPTIONS
    [--domain]   domain name, id or uuid
    #虚机可用最大内存
    --hard-limit   Max memory, as scaled integer (default KiB)
    #发生内存争用时,内存的限制
    --soft-limit   Memory during contention, as scaled integer (default KiB)
    #虚拟机加上swap的最大内存
    --swap-hard-limit   Max memory plus swap, as scaled integer (default KiB)
    #虚拟机保证分配的最小内存
    --min-guarantee   Min guaranteed memory, as scaled integer (default KiB)
    --config         affect next boot
    --live           affect running domain
    --current        affect current domain

8.2 大页和透明大页

Linux的大页内存

4KB 大小的页面在 “分页机制” 提出的时候是合理的,因为当时的内存大小不过几十兆字节。然而,当前计算机的物理内存容量已经增长到 GB 甚至 TB 级别了,操作系统仍然以 4KB 大小为页面的基本单位的话,会导致 CPU 中 MMU 的页面空间不足以存放所有的地址条目,则会造成内存的浪费。

同时,在 Linux 操作系统上运行内存需求量较大的应用程序时,采用的默认的 4KB 页面,将会产生较多 TLB Miss 和缺页中断,从而大大影响应用程序的性能。当操作系统以 2MB 甚至更大作为分页的单位时,将会大大减少 TLB Miss 和缺页中断的数量,显著提高应用程序的性能。

为了解决上述问题,自 Linux Kernel 2.6 起,引入了 Huge pages(巨型页)的概念,目的是通过使用大页内存来取代传统的 4KB 内存页面, 以适应越来越大的内存空间。Huge pages 有 2MB 和 1GB 两种规格,2MB 大小(默认)适合用于 GB 级别的内存,而 1GB 大小适合用于 TB 级别的内存。

大页实现原理

为了能以最小的代价实现大页面支持,Linux 采用了 hugetlb 和 hugetlbfs 两个概念。其中,hugetlb 是记录在 TLB 中的条目并指向 hugepages,而 hugetlbfs 则是一个特殊文件系统(本质是内存文件系统)。hugetlbfs 主要的作用是使得应用程序可以根据需要灵活地选择虚拟存储器页面的大小,而不会全局性的强制使用某个大小的页面。在 TLB 中通过 hugetlb 来指向 hugepages,可以通过 hugetlb entries 来调用 hugepages,这些被分配的 hugepages 再以 hugetlbfs 内存文件系统的形式提供给进程使用。

  • Regular Page 的分配:当一个进程请求内存时,它需要访问 PageTable 去调用一个实际的物理内存地址,继而获得内存空间。


    Regular Page
  • Huge Page 的分配:当系统配置 Huge pages 后,进程依然通过普通的 PageTable 来获取到实际的物理内存地址。但不同的是,在 Process PageTable 和 System PageTable 增加了 Hugepage(HPage)属性。


    Huge Page

    进程当需要使用 Huge pages 时,只需要声明 Hugepage 属性,让系统分配 PageTable 中的 Huge pages 条目即可实现。所以,实际上 Regular page 和 Huge page 是共享一个 PageTable 的,这就是所谓的以最小的代码来支持 Huge pages。

透明巨型页 THP

Transparent Huge pages(THP,透明大页) 自 RHEL 6 开始引入。由于传统的 Huge pages 很难手动的管理,对于程序而言,可能需要修改很多的代码才能有效的使用。THP 的引入就是为了便于系统管理员和开发人员使用大页内存。THP 是一个抽象层,能够自动创建、管理和使用传统大页。操作系统将大页内存看作是一种系统资源,在 THP 开启的情况下,其他的进程也可以申请和释放大页内存。

Huge pages 和 Transparent Huge pages 在大页内存的使用方式上存在区别,前者是预分配的方式,而后者则是动态分配的方式,显然后者更适合程序使用。需要注意的是,THP 虽然方便,但在某些场景种仍然会建议我们关闭,这个需要结合实际应用场景慎重考虑。

8.3 为虚拟机启用大页内存

例子:
在启动时分配4个1GB大页面和1024个2MB的大页面

echo 4 > /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages

将2MB和1GB的大页面挂载到主机

mkdir /dev/hugepages1G
mount -t hugetlbfs -o pagesize=1G none /dev/hugepages1G
mkdir /dev/hugepages2M
mount -t hugetlbfs -o pagesize=2M none /dev/hugepages2M

重启libvirtd,使1GB大页面可以在客户机上启用

systemctl restart libvirtd

你可能感兴趣的:(KVM学习笔记(性能优化))