关于 KVM 虚拟化的二三事整理

2020-12-29 12:04:16 浏览数 (1)

一、CPU mode 的选取

在 KVM 虚拟化中,大家对 CPU mode 的关注相对较少,多采用默认值。其实,CPU mode 的选取对 VM 的影响却很大,如果考虑不周,可能会导致稳定性差,维护成本高,影响业务等一系列问题。本文从性能,热迁移,稳定性,应用移植四个角度对 CPU mode 进行分析。

Libvirt 主要支持三种 CPU mode:

  • host-passthrough: libvirt 令 KVM 把宿主机的 CPU 指令集全部透传给 VM 。因此 VM 能够最大限度的使用宿主机 CPU 指令集,故性能是最好的。但是热在迁移时,它要求目的节点的 CPU 和源节点的一致。
  • host-model: libvirt 根据当前宿主机 CPU 指令集从配置文件 /usr/share/libvirt/cpu_map.xml 选择一种最相配的 CPU 型号。在这种 mode 下, VM 的指令集往往比宿主机少,性能相对 host-passthrough 要差一点,但是热迁移时,它允许目的节点 CPU 和源节点的存在一定的差异。
  • custom: 这种模式下 VM CPU 指令集数最少,故性能相对最差,但是它在热迁移时跨不同型号 CPU 的能力最强。此外,custom 模式下支持用户添加额外的指令集。

1、性能

三种 mode 的性能排序如下:

代码语言:javascript复制
host-passthrough > host-model > custom

但是它们的差距到底是多少呢,CERN 根据 HEPSpec06 测试标准给出了如下性能数据。

host-passthrough

host-model

custom

100%

95.84%

94.73%

从上可以总结出:

  • 这三种 CPU mode 的性能差距较小
  • 除非某些应用对某些特殊指令集有需求,否则不太建议用 host-passthrough ,原因请见后续分析。

2、热迁移

从理论上说:

  • host-passthrough: 要求源节点和目的节点的指令集完全一致
  • host-model: 允许源节点和目的节点的指令集存在轻微差异
  • custom: 允许源节点和目的节点指令集存在较大差异

故热迁移通用性如下:

代码语言:javascript复制
custom > host-model > host-passthrough

从实际情况来看,公司不同时间采购的 CPU 型号可能不相同;不同业务对 CPU 型号的要求也有差异。虽然常见多采用 intel E5 系列的 CPU,但是该系列的 CPU 也有多种型号,常见的有 Xeon,Haswell,IvyBridge,SandyBridge 等等。即使是 host-model,在这些不同型号的 CPU 之间热迁移 VM 也可能失败。所以从热迁移的角度,在选择 host-mode 时:

  • 需要充分考虑既有宿主机类型,以后采购扩容时,也需要考虑相同问题;
  • 除非不存在热迁移的场景,否则不应用选择 host-passthrough;
  • host-model 下不同型号的 CPU 最好能以 aggregate hosts 划分,在迁移时可以使用 aggregate filter 来匹配相同型号的物理机;
  • 如果 CPU 型号过多,且不便用 aggregate hosts 划分,建议使用 「custom mode」

3、稳定性

从使用经验来看,host-model 和 custom 模式下的 VM 运行稳定,而 host-passthrough 则问题比较大,特别是在 centos6 内核下,常常出现宿主机 kernel panic 问题,如:

  • Redhat-6.4_64bit-guest kernel panic with cpu-passthrough and guest numa

所以从稳定性出发:

  • 2.6 内核及更早内核版本避免使用 host-passthrough
  • 「custom/host-model」 比较稳定

4、应用移植

对应用的影响主要体现在编译型应用,如 C,C ,Golang。在物理机上编译好的二进制应用,直接移植到 custom mode 的 VM 有可能出现 illegal instruction。其中最常见的 SSE4 类型指令集异常,因为 custom 模式下没有 SSE4 指令集,而在物理机或者其它 mode 的 VM 是有该指令集的。

从经验来看:

  • host-model 能够平滑移植绝大部分编译型二进制文件。
  • custom 下的 VM 如果出现 illegal instruction,在该 VM 重新编译(有时需要修改编译参数)应用后,一般能正常运行。
  • 如果公司存在大量编译型应用,「host-model」 能让业务上云更平滑些。

二、搭建几点

1、初始化网卡

因为 centos7 默认网卡发生改变,我们需要修改内核参数,使用 eth0 作为网卡:

修改内核参数

光标移动到 Install CentOS 上,按 tab 键 输入net.ifnames=0 biosdevname=0 回车

2、分区

我们不分交换分区,因为公有云上的云主机都是没有交换分区的:

分配标准分区:

分区1

分区2

3、 VM 网络

VM 网络

重启/etc/init.d/network restart 或者systemctl restart network

4、安装软件包

安装的常用企业运维基础工具包:

代码语言:javascript复制
yum install tree nmap dos2unix lrzsz nc lsof wget tcpdump htop iftop iotop sysstat nethogs net-tools -y

三、libvirtd 日志

配置文件位置:

代码语言:javascript复制
/etc/libvirt/libvirtd.conf

日志配置:

代码语言:javascript复制
#将日志级别设置为 1(调试)
log_level = 1

#指定日志输出文件名称
log_outputs="1:file:/var/log/libvirt/libvirtd.log"

注意:
libvirtd. 日志文件可能会飞速增长。 用户应配置logrotate ,否则 /var 文件系统最后会装满内容。
以上的日志的输出级别为debug级别.这个级别的日志是最多的,一般只在开发以及测试的时候使用.而在生产运行环境中,日志的级别为info,warn,error,fatal. 以下前面的数字为他们的level.

1 debug
2 info
3 warn
4 error
5 fatal

重启 libvirtd:

代码语言:javascript复制
/etc/init.d/libvirtd restart

如果在目录下还是没发现日志文件,那么你可能需要使用一下命令来运行 libvirtd:

代码语言:javascript复制
libvirtd --daemon --listen --config /etc/libvirt/libvirtd.conf

四、快速克隆VM

1、本机克隆

现有本地 VM 需要先停止。查看本地VM:

代码语言:javascript复制
$ virsh list --all
 Id    名称                         状态
---------------------------------------------------
 -     vm-k8s                         关闭

从 vm-k8s 克隆一个 vm-master1,执行克隆操作,使用磁盘文件 vm-master1.img

代码语言:javascript复制
virt-clone -o generic -n vm-k8s -f /data/image/vm-master1.img

启动 VM:

代码语言:javascript复制
virsh start vm-master1

启动后修改主机名、IP等

2、复制配置文件和硬盘文件跨机克隆

查看现有 VM:

代码语言:javascript复制
$  virsh list --all
Id    Name                           State
----------------------------------------------------
 8    vm-k8s                         running

这里将从 vm-k8s 克隆另一个 vm-master2导出 vm-k8s 配置文件

代码语言:javascript复制
virsh dumpxml vm-k8s > vm-master2.xml

查看 vm-k8s 磁盘文件所在位置:

代码语言:javascript复制
$ virsh edit vm-k8s
<source file='/data/image/vm-k8s.img'/>

复制 vm-k8s 磁盘文件为 vm-master2.img

代码语言:javascript复制
cd /data/image
cp vm-k8s.img vm-master2.img

通过 SCP 把磁盘文件和配置文件复制到目标机器。

修改 vm-master2.xml

代码语言:javascript复制
<domain type='kvm' id='10'>
<name>`vm-master2</name>
  <uuid>fe1f692d-34d5-4e0c-ab36-ba84eb024ee5</uuid>
……
<source file='/data/image/vm-master2.img'/>
……

定义 vm-master2 配置文件:

代码语言:javascript复制
$ virsh define vm-master2.xml
Domain vm-master2 defined from vm-master2.xml

此时会看到 vm-master2 已经生成

代码语言:javascript复制
$ virsh list –all
Id    Name                           State
----------------------------------------------------
-     vm-master2                    shut off

启动 vm-master2,重新更改主机名、IP等。

五、性能优化

1、CPU优化

kvm 是一个进程,是受 CPU 的调度,对于物理 CPU,同一个 core 的 threads 共享 L2 Cache,同一个 socket 的 cores 共享 L3 cache,所以 VM 的 vcpu 应当尽可能在同一个 core 和 同一个 socket 中,增加 cache 的命中率,从而提高性能。IBM 测试过,合理绑定 vcpu 能给 JVM 来的 16% 的性能提升。

VM vcpu 尽可能限定在一个 core 或者一个 socket 中。例如:当 vcpu 为 2 时,2 个 vcpu 应限定在同一个 core 中,当 vcpu 大于 2 小于 12 时,应限定在同一个 socket 中。

我们可以使用 taskset 来进行操作:

代码语言:javascript复制
$ taskset -cp 0 8337
pid 8337's current affinity list: 0-3

# 表示当前8337会在0-3CPU上调度
pid 8337's new affinity list: 0

#表示当前8337会在cpu0上进行调度
8377 是进程号,通过 ps -ef|grep kvm 来获取到
-p pid 指定进程
-c 指定cpu(可以写多个)

提示:可以减少开机 miss,性能可以提高10%

2、内存优化

2.1、关闭 KSM

当 Linux 启用了KSM 之后,KSM 会检查多个运行中的进程,并比对它们的内存。如果任何区域或者分页是一样的,KSM 就会毫不犹豫地合并他们成一个分页。那么新分页也是被标记成 copy on write。如果 VM 要修改内存的话,那么 Linux 就会分配新的内存给这个VM。

优点:

  • 一个 VM 启动,则只继承了父进程(qemu-kvm)的内存。一台 VM 的内存,可以让相同操作系统或者运行相同应用的 VM共享。
  • 当开启了 KSM,常用的进程数据存在缓存和主内存中。这样可以减少 VM 的缓存未命中,同时也提高了 VM 性能。
  • 共享内存降低了 VM 的总体内存使用率,从而允许更高的密度和更大的资源利用率。

缺点:

  • 利用 KSM 使内存超用。这会导致消耗一定的计算资源用于内存扫描,加重了 CPU 的消耗。内存超用,使得频繁地使用 swap 交互,导致 VM 性能下降。
  • KSM使用了边通道(side channels),可能存在泄露客户信息的潜在风险。为此就要考虑在 VM 上关闭 KSM。

所以总结一下应用的场景:

  • 生产环境慎用,应急时可开启。
  • 测试环境建议使用。
  • 桌面虚拟化环境建议使用,但要注意内存使用情况。

关闭 KSM:

1)禁止某个访客与其他访客共享内存,XML文件可配置为:

代码语言:javascript复制
<memoryBacking>
    <nosharepages/>
</memoryBacking>

2)禁止所有访客直接共享内存,主机配置为:

代码语言:javascript复制
echo 0 > /sys/kernel/mm/ksm/pages_shared
echo 0 > /sys/kernel/mm/ksm/pages_sharing
2.2、打开 huge page

KVM Guest 可以开启大的页内存支持,从而通过增加事务后备缓冲区(TLB)的 CPU 缓存命中率来提高性能。

打开透明大页方式有两种:

  1. 允许某个 Guest 开启透明大页
代码语言:javascript复制
<memoryBacking>
   <hugepages/>
</memoryBacking>
代码语言:javascript复制
echo 25000 > /pro c/sys/vm/nr_hugepages
mount -t hugetlbfs hugetlbfs /dev/hugepages
service libvirtd restart
  1. 允许 Host 中所有 Guest 开启透明大页
代码语言:javascript复制
echo always > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
echo 0 > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag

3、IO 优化

kvm 就使用 virtio。

❝Virtio是一种半虚拟化技术,让磁盘知道你是运行在 VM 里面。这是一种半虚拟化技术,有兴趣可以了解一下。 ❞

3.1、IO cache

kvm 支持多种 VM 多种 IO Cache 方式:writeback, none, writethrough 等。

  • 性能上:writeback > none > writethrough
  • 安全上:writeback < none < writethrough。

IO cache

权衡安全性和性能,KVM 推荐使用 none:

代码语言:javascript复制
<disk type='file' device='disk'>
  <driver name='qemu' type='qcow2' cache='none'/>  #  cache 可为 writeback, none, writethrough,directsync,unsafe 等
  ...
</disk>
3.2、调度算法

Linux kernel 提供了三种 Disk IO 的调度策略,分别为 noop,deadline,cfq。(CentOS 6 有四种)

  • noop: noop is often the best choice for memory-backed block devices (e.g. ramdisks) and other non-rotational media (flash) where trying to reschedule I/O is a waste of resources
  • deadline: deadline is a lightweight scheduler which tries to put a hard limit on latency
  • cfq: cfq tries to maintain system-wide fairness of I/O bandwidth

相关资料:

  • http://www.cnblogs.com/zhenjing/archive/2012/06/20/linux_writeback.html
  • http://jackyrong.iteye.com/blog/898938

由于一个宿主机上会运行大量 VM ,为了防止某个因某个 VM 频繁的 IO 操作影响其它 VM ,所以应该选择 cfq 这种公平的调度策略。

查看当前调度算法

代码语言:javascript复制
$ cat /sys/block/sda/queue/scheduler 
noop [deadline] cfq

更改调度算法如下:

代码语言:javascript复制
echo “noop” > /syc/block/sda/queue/scheduler
3.3、磁盘格式

KVM 常用 Raw 和 Qcow2 格式作为 VM 的镜像文件。对 VM 而言,通俗的说,Raw 格式相当于裸盘,Qcow2 是 copy on write,二者对比如下:

  • 性能:Raw > Qcow2
  • 节省空间:Qcow2 > Raw
  • 安全:Qcow2 > Raw

Qcow2 格式发展到现在,已经有和 Raw 相近的性能,同时能较好的节省空间,所以推荐使用 「Qcow2」 镜像,但是要最大可能的发挥性能,使用 Raw 格式也未尝不可。

4、网络优化

4.1、启用 vhost_net

VhostNet provides better latency (10% less than e1000 on my system) and greater throughput (8x the normal virtio, around 7~8 Gigabits/sec here) for network.

代码语言:javascript复制
modprobe vhost-net
4.2、网卡多队列

对 VM 而言,virtio-net 不能并行的处理网络包,当网络流量很大时,单个 vCPU 有限的处理能力将直接影响 VM 的网络流量,所以可以通过多队列的 virtio-net 提高 VM 网络吞吐量。

网卡多队列

代码语言:javascript复制
  <devices>
    <interface type='network'>
      ...
      <driver name='vhost' txmode='iothread' ioeventfd='on' event_idx='off' queues='N'/>  # queues=N
    </interface>
  </devices>

vm 查看队列是否生效:

代码语言:javascript复制
$ ll /sys/class/net/eth0/queues/
总用量 0
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-0
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-1
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-2
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-3
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-4
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-5
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-6
drwxr-xr-x 2 root root 0 12月 20 01:24 rx-7
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-0
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-1
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-2
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-3
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-4
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-5
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-6
drwxr-xr-x 3 root root 0 12月 20 01:24 tx-7

六、小结

最后用一张脑图小结一下:

小结

参考资料:

  • [1]:http://wsfdl.com/openstack/2018/01/02/libvirt_cpu_mode.html
  • [2]:http://wsfdl.com/openstack/2014/11/17/Nova-KVM性能调优.html
  • [3]:http://www.linux-kvm.org/page/Multiqueue
  • [4]:https://i4t.com/1627.html

0 人点赞