[ kvm ] 学习笔记 4:KVM 高级功能详解

1. 半虚拟化驱动

1.1 virtio 概述

KVM 是必须使用硬件虚拟化辅助技术(如 Intel VT-x 、AMD-V)的 Hypervisor,在CPU 运行效率方面有硬件支持,其效率是比较高的;在有 Intel EPT 特性支持的平台上,内存虚拟化的效率也较高。 QEMU/KVM 提供了全虚拟化环境,可让客户机不通过任何修改就能运行在 KVM 环境中。不过 KVM 在 I/O虚拟化方面,传统的方式是使用 QEMU 纯软件的方式来模拟 I/O 设备(如网卡、磁盘、显卡等),其效率并不很是高。前端

  CPU 和 内存的虚拟化由KVM内核模块提供,I/O设备虚拟化由QEMU负责实现。node

在KVM中,能够在客户机中使用半虚拟化驱动的方式是采用 Virtio 这个 Linux 上的设备驱动标准框架。mongodb

 

彻底虚拟化:GuestOS 运行在物理机上的 Hypervisor 之上,GuestOS 并不知道它已经被虚拟化,并不须要任何修改就能工做;windows

半虚拟化:GuestOS 不只知道它运行在 Hypervisor 之上,还包括让 GuestOS 更高效的过分到 Hypervisor 的代码。后端

 

在彻底虚拟化模式中,hypervisor 必须模拟设备硬件,它是在会话的最低级别进行模拟的,尽管在该抽象中模拟很干净,但它同时也是最低效的,最复杂的。缓存

在半虚拟化中,GuestOS 和 hypervisor 可以共同合做,让模拟更加高效,缺点是操做系统知道它被虚拟化,而且须要修改才能工做。安全

 

左图在传统的彻底虚拟化环境中,hypervisor必须捕捉这些请求,而后模拟物理硬件的行为。尽管这也作提供很大的灵活性(即运行未更改的操做系统),但它的效率比较低.bash

右图,半虚拟化,来宾操做系统知道它运行在hypervisor之上,并包含了充当当前的驱动程序.hypervisor为特定的设备模拟实现后端驱动程序.经过在这些前端和后端驱动程序中的virtio,为开发模拟设备提供标准化接口,从而增长代码的跨平台重用率并提升效率.服务器

 

QEMU模拟 I/O 设备基本原理和优缺点网络

 

使用QEMU模拟 I/O 的状况下:

  (1)当客户机中的设备驱动程序(device driver)发起 I/O 操做请求时,KVM模块中的 I/O 操做捕获代码会拦截此次 I/O 请求;

  (2)通过处理后将本次 I/O 请求的信息存放到 I/O 共享页,并通知用户控件中的 QEMU 程序;

  (3)QEMU 模拟程序得到 I/O 操做的具体信息以后,交由硬件模拟代码来模拟出本次的 I/O 操做;

  (4)完成以后,将结果放回到 I/O 共享页,并通知KVM 模块中的 I/O 操做捕获代码;

  (5)由 KVM 模块中的捕获代码读取 I/O 共享页中的操做结果,并把结果返回到客户机中。

在这个过程当中,QEMU进程在等待I/O时被阻塞,当客户机经过 DMA 访问大块 I/O时,QEMU模拟程序将不会把操做结果放到I/O共享页中,而是经过内存映射的方式将结果直接写到客户机的内存中去,而后经过KVM模块告诉客户机DMA操做已经完成。

QEMU 模拟 I/O 设备的方式,其优势是能够经过软件模拟出各类各样的硬件设备,包括一些不经常使用的或者很老很经典的设备,并且它不用修改客户机操做系统,就能够实现模拟设备在客户机中正常工做。 在KVM客户机中使用这种方式,对于解决手上没有足够设备的软件开发及调试有很是大的好处。而它的缺点是,每次 I/O 操做的路径比较长,有较多的 VMEntry、VMExit发生,须要屡次上下文切换(context switch),也须要屡次数据复制,因此它的性能较差。

 

半虚拟化 virtio 的基本原理和优缺点

其中前端驱动(frondend,如 virtio-blk、virtio-net等)是在客户机中存在的驱动程序模块,然后端处理程序(backend)是在 QEMU中实现的。

在这先后端驱动之间,还定义了两层来支持客户机与 QEMU 之间的通讯:

  virtio:虚拟队列接口,在概念上将前端驱动程序附加到后端处理程序,一个前端驱动程序可使用 0 个或 多个队列,具体数据取决于需求;

  例如:virtio-net 网络驱动程序使用两个虚拟队列(一个用于接收、另外一个用于发送),而virtio-blk块驱动程序仅使用一个虚拟队列。虚拟队列实际上被实现为跨越客户机操做系统和hypervisor的衔接点,但它能够经过任意方式实现,前提是客户机操做系统和virtio后端程序都遵循必定的标准,以相互匹配的方式实现它。

  virtio-ring:实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息,而且它们能够一次性保存前端驱动的屡次I/O请求,而且交由后端去批量处理,最后实际调用宿主机中设备驱动实现物理上的I/O操做,这样作就能够根据约定实现批量处理而不是客户机中每次I/O请求都须要处理一次,从而提升客户机与hypervisor信息交换的效率。

virtio 半虚拟化驱动的方式,能够得到很好的I/O性能,其性能几乎能够达到和 native(非虚拟化环境中的原生系统)差很少的I/O性能。因此,在使用 kvm 时,若是宿主机内核和客户机都支持 virtio的状况下,通常推荐使用 virtio 达到更好的性能。

 

virtio 缺点:

  必需要安装特定的virtio驱动使其知道是运行在虚拟化环境中,且按照 virtio 的规定格式进行数据传输,不过客户机中可能有一些老的Linux系统不支持virtio 和主流windows系统须要安装特定的驱动才支持 virtio,不过,较新的一些Linux发行版(如RHEL 6.三、Fedora 17等)默认都将virtio相关驱动编译为模块,可直接做为客户机使用virtio,并且对于主流Windows系统都有对应的virtio驱动程序可供下载使用。

virtio是对半虚拟化hypervisor中的一组通用模拟设备的抽象.该设置还容许hypervisor导出一组通用的模拟设备,并经过一个通用的应用程序接口(API)让它们变得可用.有了半虚拟化hypervisor以后,来宾操做系统可以实现一组通用的接口,在一组后端驱动程序以后采用特定的设备模拟.后端驱动程序不须要是通用的,由于它们只实现前端所需的行为.

注意,在现实中(尽管不须要),设备模拟发生在使用 QEMU 的空间,所以后端驱动程序与 hypervisor 的用户空间交互,以经过 QEMU 为 I/O 提供便利。QEMU 是一个系统模拟器,它不只提供来宾操做系统虚拟化平台,还提供整个系统(PCI 主机控制器、磁盘、网络、视频硬件、USB 控制器和其余硬件元素)的模拟。   

 

1.2 安装 virtio 驱动

Linux 2.6 及以上版本内核都是支持 virtio 的。因为 virtio 的后端处理程序是在位于用户空间的 QEMU 中实现的,因此,在宿主机中只须要比较新的内核便可,不须要特别的编译与 virtio 相关的驱动。

 

1.2.1 Linux 中的 virtio 驱动

[root@192.168.118.14 ~]#lsmod | egrep virt
virtio_balloon         13664  0 
virtio_blk             18156  3 
virtio_console         28114  0 
virtio_net             28024  0 
virtio_pci             22913  0 
virtio_ring            21524  5 virtio_blk,virtio_net,virtio_pci,virtio_balloon,virtio_console
virtio                 15008  5 virtio_blk,virtio_net,virtio_pci,virtio_balloon,virtio_console

其中,virtio,virtio_ring、virtio_pci 等驱动程序提供了对 virtio API 的基本支持,是使用任何 virtio 前端驱动都必须使用的,并且它们的加载还有必定的顺序,应该按照 virtio、virtio_ring、virtio_pci 的顺序加载,而 virtio_net、virtio_blk 这样的驱动能够根据实际须要进行选择性的编译和加载。

 

1.3 使用 virtio_balloon

 

(1)ballooning 简介

一般来讲,要改变客户机占用的宿主机内存,要先关闭客户机,修改启动的内存配置,而后重启客户机才能实现。而内存的 ballooning (气球)技术能够在客户机运行时动态的调整它所占用的宿主机内存资源,而不须要关闭客户机。

ballooning 技术形象的在客户机占用的内存中引入气球(balloon)的概念。气球中的内存是能够供宿主机使用的,因此,当宿主机内存紧张,空余内存很少时,能够请求客户机回收利用已分配给客户机的部份内存,客户机就会释放其空闲的内存,此时若客户机空闲内存不足,可能还会回收部分使用中的内存,可能会将部份内存换出到客户机的交换分区(swap)中,从而使内存气球充气膨胀,进而使宿主机回收气球中的内存用于其余进程。反之,当客户机中内存不足时,也可让宿主机的内存气球压缩,释放出内存气球中的部份内存,让客户机使用更多的内存。

目前不少虚拟机,如KVM 、Xen、VMware 等,都对 ballooning 技术提供了支持。

 

(2)KVM 中 ballooning 的原理及优劣势

KVM 中 ballooning 的工做过程主要有以下几步:

  1. Hypervisor 发送请求到客户机操做系统让其归还必定数量的内存给 Hypervisor;

  2. 客户机操做系统中 virtio_balloon 驱动接收到 Hypervisor;

  3. virtio_balloon 驱动使客户机的内存气球膨胀,气球中的内存就不能被客户机访问。若是此时客户机中内存剩余量很少,而且不能让内存气球膨胀到足够大的以知足 Hypervisor 的请求,那么 virtio_balloon 驱动也会尽量多的提供内存使气球膨胀,尽可能去知足 Hypervisor 的请求中的内存数量;

  4. 客户机操做系统归还气球中的内存给 Hypervisor;

  5. Hypervisor 能够将从气球中得来的内存分配到任何须要的地方;

  6. 即便从气球中获得的内存没有处于使用中,Hypervisor 也能够将内存返还给客户机中,这个过程为:Hypervisor 发请求到客户机的 virtio_balloon 驱动;这个请求使客户机操做系统压缩内存气球;在气球中的内存被释放出来,从新由客户机访问和使用。

 

ballooning 在节约内存和灵活分配内存方面有明显的优点:

  1. 由于ballooning 可以被控制和监控,因此可以潜在的节约大量的内存;

  2. ballooning 对内存的调节很灵活,便可以精细的请求少许内存,又能够粗旷的请求大量的内存;

  3. Hypervisor 使用 ballooning 让客户机归还部份内存,从而缓解其内存压力。并且从气球中回收的内存也不要求必定要被分配给另外某个进程。

 

从另外一方面来讲,KVM 中 ballooning的使用不方便、不完善的地方也是存在的,其缺点以下:
  1. ballooning 须要客户机操做系统加载 virt_balloon 驱动,然而并不是每一个客户机系统都有该驱动;

  2. 若是有大量内存须要从客户机系统中回收,那么 ballooning 可能会下降客户机操做系统运行的性能。一方面,内存的减小可能会让客户机中做为磁盘数据缓存的内存被放到气球中,从而使客户机中的磁盘I/O访问增长;另外一方面,若是处理机制不够好,也可能让客户机中正在运行的进程因为内存不足而执行失败;

  3. 目前没有比较方便的、自动化的机制来管理 ballooning,通常采用在 QEMU monitor 中执行 balloon 命令来实现 ballooning。没有对客户机的有效监控,没有自动化的ballooning 机制,这可能会使在生产环境中实现大规模自动化部署不是很方便。

  4. 内存的动态增长或减小,可能会使内存被过分碎片化,从而下降内存使用时的性能。

 

(3)KVM 中 ballooning 使用示例

1. 建立虚拟机
[root@192.168.118.14 ~]#qemu-kvm -smp 1 -m 1024 -balloon virtio /images/cirros-0.3.5-i386-disk.img --nographic

2. 查看 PCI 设备是否加载
# lspci -k
00:00.0 Class 0600: 8086:1237
00:01.0 Class 0601: 8086:7000
00:01.1 Class 0101: 8086:7010 ata_piix
00:01.3 Class 0680: 8086:7113
00:02.0 Class 0300: 1013:00b8
00:03.0 Class 0200: 8086:100e e1000
00:04.0 Class 00ff: 1af4:1002 virtio-pci

能够发现,00:04.0 Class 00ff: 1af4:1002 virtio-pci 就是 virtio-pci 设备


3. 经过 balloon 调整内存大小

原内存
# free -m 
             total         used         free       shared      buffers
Mem:          1001           12          988            0            0
-/+ buffers:                 12          989
Swap:            0            0            0


使用 qemu-monitor 减小内存大小
(qemu) info balloon
balloon: actual=1024
(qemu) balloon 512
(qemu) info balloon
balloon: actual=512

4. 查看调整后的内存大小
# free -m 
             total         used         free       shared      buffers
Mem:          489           12          477            0            0
-/+ buffers:                 12          234
Swap:            0            0            0

 

总的来讲,对于 ballooning 技术,目前尚未彻底成熟的管理控制工具,大规模部署很是不方便,并且性能没有很大的提高,建议慎用。

 

1.4 使用 virtio_net

在选择KVM中的网络设备时,通常来讲优先选择半虚拟化的网络设备而不是模拟纯软件模拟的设备使用 virtio_net 半虚拟化驱动,能够提升网络吞吐量和下降网络延迟,从而让客户机中网络达到几乎和非虚拟化系统中使用原生网卡的网络差很少的性能。

(1)检查 QEMU 是否支持 virtio 类型的网卡

# qemu-kvm -smp 2 -m 512m -net nic,model=?
qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio

(2)启动客户机时,指定分配 virtio 网卡设备

# qemu-kvm -smp 2 -m 512m \
-drive file=/root/cirros-0.3.5-i386-disk.img,if=virtio -net nic,model=virtio -net tap,name=tap0,script=no -daemonize 

 使用 virtio_net 依然是较低的性能,能够检查宿主机系统中对 GSO 和 TSO 特性的设置。关闭 GSO 和 TSO 可使用半虚拟化网络驱动的性能更加优化。

ethtool -K eno1 gso off
ethtool -K eno1 tso off

 

用 vhost_net 后端驱动

前面提到 virtio 在宿主机中的后端处理程序(backend)通常是由用户空间的 QEMU 提供的,然而,若是对于网络 IO 请求的后端处理可以在内核空间来完成,则效率更高,会提升网络吞吐量和减小网络延迟。在比较新的内核中有一个叫作 “vhost_net”的驱动模块,它做为一个内核级别的后端处理程序,将 virtio-net的后端处理任务放到内核空间执行,从而提升效率。

qemu-kvm -smp 2 -m 512m \
-drive file=/root/cirros-0.3.5-i386-disk.img,if=virtio \
-net nic,model=virtio,macaddr=52:54:00:ac:0f:11 \
-net tap,name=tap0,vnet_hdr=on,vhost=on,script=no \
-daemonize

通常来讲,使用 vhost-net 做为后端处理驱动能够提升网络的性能。不过,对于一些使用 vhost-net 做为后端的网络负载类型,可能使其性能不升反降。特别是从宿主机到其客户机之间的 UDP 流量,若是客户机处理接受数据的速度比宿主机发送的速度要慢,这时就容易出现性能降低。在这种状况下,使用 vhost-net 将会使 UDP socket 的接受缓冲区更快的溢出,从而致使更多的数据包丢失。所以在这种状况下不使用vhost-net,让传输速度稍慢一点,反而会提升总体的性能。

 

1.5 使用 virtio_blk

virtio_blk 驱动使用 virtio API 为客户机提供了一个高效访问块设备 I/O 方法。在 QEMU/KVM 中对块设备使用 virtio,须要在两方面进行配置:客户机中的前端驱动模块 virtio_blk 编译为内核模块,能够做为客户机直接使用 virtio_blk。

启动一个使用 virtio_blk 做为磁盘驱动的客户机,其 qemu-kvm 命令行以下:

[root@192.168.118.14 ~]#qemu-kvm -smp 2 -m 512m -drive file=/images/cirros-0.3.5-i386-disk.img,if=virtio
未使用 virtio 模块的虚拟机
# lsblk 
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0  39.2M  0 disk 
`-sda1   8:1    0  31.4M  0 part /


使用 virtio 模块的虚拟机
# lsblk 
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
vda    253:0    0  39.2M  0 disk 
`-vda1 253:1    0  31.4M  0 part /

 

2. 动态迁移

 

2.1 动态迁移概念

迁移(migration)包括系统总体的迁移和某个工做负载的迁移。系统总体迁移,是将系统上的全部软件彻底复制到另外一台物理硬件机器上。而工做负载的迁移,是将系统上的某个工做负载转移到另外一台物理机上继续运行。服务器系统迁移的做用在于简化了系统维护管理,提升了系统负载均衡,加强了系统容错性并优化了系统电源管理。

在虚拟化环境中的迁移,又分为 静态迁移(static migration)和动态迁移(live migration) 静态迁移和动态迁移最大的区别:静态迁移有明显一段时间客户机中的服务不可用,而动态迁移则没有明显的服务暂停时间。

虚拟化中的静态迁移,也能够分为两种,一种是关闭客户机后,将其硬盘镜像复制到另外一台宿主机上而后恢复启动起来,这种迁移不能保留客户机中运行的工做负载;另外一种是两台宿主机共享存储系统,只须要暂停客户机后,复制其内存镜像到另外一台宿主机中恢复启动,这种迁移能够保持客户机迁移前的内存状态和系统运行的工做负载。

动态迁移,是指在保证客户机上应用服务正常运行的同时,让客户机在不一样的宿主机之间进行迁移,其逻辑步骤与前面静态迁移几乎一致,有硬盘存储和内存都复制的动态迁移,也有仅复制内存镜像的动态迁移。不一样的是,为了保证迁移过程当中客户机服务的可用性,迁移过程仅有很是短暂的停机时间。动态迁移容许系统管理员将客户机在不一样物理机上迁移,同时不会断开访问客户机中服务的客户端或应用程序的链接。一个成功的动态迁移,须要保证客户机的内存、硬盘存储、网络链接在迁移到目的的主机后依然保持不变,并且迁移过程的服务暂停时间较短。

 

2.2 动态迁移的效率和应用场景

虚拟机迁移主要加强了系统的可维护性,其主要目标是在客户没有感受的状况下,将客户机迁移到了另外一台物理机上,并保证其各个服务都正常使用。能够从以下几个方面来衡量虚拟机的迁移的效率:

(1)总体迁移时间:从源主机中迁移操做开始到客户机被迁移到目的主机并恢复其服务所花费的时间;

(2)服务器停机时间:在迁移过程当中,源主机和目的主机上客户机的服务都处于不可用状态的时间,此时源主机上客户机已暂停服务,目的主机上客户机还未恢复服务;

(3)对服务的性能影响:不只包括迁移后的客户机中应用程序的性能与迁移前相比是否有所降低,还包括迁移后对目的主机上的其余服务的性能影响。

 

动态迁移的好处很是明显,动态迁移的几个场景:

(1)负载均衡:当一台物理服务器的负载较高时,能够将其上运行的客户机动态迁移到负载较低的宿主机服务器中,以保证客户机的服务质量(QoS)。

(2)解除硬件依赖:升级主机,添加某些硬件设备时,能够将宿主机上运行的客户机很是安全高效的动态迁移到其余宿主机上。

(3)节约能源:经过动态迁移将宿主机上的客户机集中迁移到其中几台服务器上。

(4)实现客户机地理位置上的远程迁移:好比跨地域性的迁移。

 

2.3 KVM 动态迁移原理与实践

在KVM 中,即支持离线的静态迁移,又支持在线的动态迁移。对于静态迁移,能够在源宿主机上某客户机的 QEMU monitor中,用 "savevm my_tag" 命令来保存一个完整的客户机镜像快照(标记为 my_tag),而后在源宿主机中关闭或暂停该客户机,而后将该客户机的镜像文件复制到另一台宿主机中,用于源主机中启动客户机时以相同的命令启动复制过来的镜像,在其 QEMU monitor 中用 "loadvm my_tag" 命令来恢复刚才保存的快照便可彻底加载保存快照时的客户机状态。这里的 "savevm" 命令保存的完整客户机状态包括:CPU 状态、内存、设备状态、可写磁盘中的内容。注意:这种保存快照的方法须要 qcow二、qed 等格式的磁盘镜像文件,由于只有它们才支持快照这个特性。

若是源宿主机和目的宿主机共享存储系统,则只须要经过网络发送客户机的vCPU 执行状态、内存中的内容、虚拟设备的状态到目的主机上。不然,还须要将客户机的磁盘存储发送到目的主机上去。

 

在不考虑磁盘存储复制的状况下(基于共享存储系统),KVM 动态迁移的具体迁移过程为:在客户机动态迁移开始后,客户机依然在原宿主机上运行,与此同时,客户机的内存页被传输到目的主机之上。QEMU/KVM 会监控并记录下迁移过程当中全部已被传输的内存页的任何修改,并在全部的内存页都被传输完成后即开始传输在前面过程当中内存页的更改内容。QEMU/KVM 也会估计迁移过程当中的传输速度,当剩余的内存数据量可以在一个可设定的时间周期内传输完成之时,QEMU/KVM 将会关闭源宿主机上的客户机,再将剩余的数据量传输到目的主机上去,最后传输过来的内存内容在目的宿主机上恢复客户机的运行状态。至此,KVM的一个动态迁移操做就完成了。

当客户机中内存使用量很是大且修改频繁,内存中数据被不断修改的速度大于 KVM 可以传输的内存速度之时,动态迁移过程是不会完成的,这时要进行迁移只能进行静态迁移。

 

对于 KVM 动态迁移,有以下几点建议和注意事项:

  (1)源宿主机和目的宿主机之间尽可能用网络共享的存储系统来保存客户机镜像,尽管KVM动态迁移也支持连通磁盘镜像一块儿复制。共享存储(如NFS)在源宿主机和目的宿主机上的挂载位置必须一致;

  (2)为了提升动态迁移的成功率,尽可能在同类型 CPU 的主机上面进行动态迁移;

  (3)64 位的客户机只能在 64位宿主机之间迁移,而 32 位客户机能够在 32 位宿主机和 64 位宿主机之间迁移;

  (4)动态迁移的源宿主机和目的宿主机对 NX 位的设置是相同的,要么关闭状态,要么打开状态;

  (5)在进行动态迁移时,被迁移客户机的名称是惟一的,在目的宿主机上不能与源宿主机中被迁移客户机同名的客户机存在;

  (6)目的宿主机和源宿主机的软件配置尽量是相同,例如,为了保证动态迁移后客户机中网络依然正常工做,须要在目的宿主机上配置和源宿主机相同名称网桥,并让客户机以桥接的方式使用网络。

 

示例:使用 qemu-kvm 动态迁移

 

NFS 主机配置:

[root@192.168.118.16 ~]#mkdir /images
[root@192.168.118.16 ~]#mv cirros-0.3.5-i386-disk.img  /images/
[root@192.168.118.16 ~]#yum install nfs-utils -y
[root@192.168.118.16 ~]#cat /etc/exports
/images *(rw,async,no_root_squash)

[root@192.168.118.16 ~]#systemctl start rpcbind
[root@192.168.118.16 ~]#systemctl start nfs-server

 

源宿主机配置:

[root@192.168.118.14 ~]#yum install nfs-utils -y
[root@192.168.118.14 ~]#mount 192.168.118.16:/images /images/
[root@192.168.118.14 ~]#qemu-kvm -smp 2 -m 512m /images/cirros-0.3.5-i386-disk.img -monitor stdio

目的迁移主机操做以下:

[root@192.168.118.15 ~]#yum install nfs-utils -y
[root@192.168.118.15 ~]#mount 192.168.118.16:/images /images/
[root@192.168.118.15 ~]#qemu-kvm -smp 2 -m 512m /images/cirros-0.3.5-i386-disk.img -incoming tcp:0:6666

经过 tigervnc 链接:

 

到此,在源宿主机执行:

(qemu) migrate -d tcp:192.168.118.15:6666

 

再次查看,被迁移的主机:

被迁移主机完成后,也存在运行top命令,迁移完成。

 

QEMU/KVM 中也支持增量复制磁盘修改部分数据(使用相同的后端镜像时)的动态迁移,以及直接复制整个客户机磁盘镜像的动态迁移。使用相同后端镜像文件的动态迁移过程以下,与前面直接使用NFS共享存储很是相似。

(1)在源宿主机上,根据一个后端镜像文件,建立一个 qcow2 格式的镜像文件,并启动客户机,命令以下:

[root@192.168.118.14 /images]#qemu-img create -f qcow2 -o backing_file=/images/cirros-0.3.5-i386-disk.img,size=20G kvm1.qcow2
[root@192.168.118.14 ~]#qemu-kvm -smp 2 -m 512m /root/kvm1.qcow2 -monitor stdio

(2)在目的宿主机上,也创建相同的 qcow2 格式的客户机镜像,并带有 "-incoming" 参数来启动客户机使其处于迁移监听状态:

[root@192.168.118.15 ~]#qemu-img create -f qcow2 -o backing_file=/images/cirros-0.3.5-i386-disk.img,size=20G kvm1.qcow2
[root@192.168.118.15 ~]#qemu-kvm -smp 2 -m 512m /root/kvm1.qcow2 -incoming tcp:0:6666

(3)在源宿主机上的客户机的 QEMU monitor 中,运行 "migrate -i tcp:192.168.118.15:6666"

注意:有些 qemu-kvm 并不支持 -i 增量迁移,能够直接使用:migrate tcp:192.168.118.15:6666
(qemu) migrate tcp:192.168.118.15:6666

 

至此,基于相同后端镜像的磁盘动态迁移就完成,在目的宿主机上能够看到迁移过来的客户机已经处于和源客户机同样的状态。

 

3. KSM 技术

在现代操做系统中,共享内存是一个很广泛应用的概念。如在 Linux 系统中,当使用 fork 函数建立一个进程时,子进程与父进程共享所有的内存,而当子进程或父进程试图修改它们的共享内存区域时,内核会分配一块新的内存区域,并将试图修改的共享内存区域复制到新的内存区域上,而后让进程去修改复制的内存。这就是著名的“写时复制”(copy-on-write)技术。而 KSM技术却与这种内存共享概念有点相反。

KSM 是“Kernel SamePage Merging”缩写,中文可称为“内核同页合并”。KSM 容许内核在两个或多个进程之间共享彻底相同的内存页。KSM 让内核扫描检查正在运行中的程序并比较它们的内存,若是发现它们有内存区域或内存页是彻底相同的,就将相同的内存合并为一个单一的内存页,并将其标识为“写时复制”。这样能够起到节省系统内存使用量的做用。以后,若是有进程试图去修改被标识为“写时复制”的合并的内存页时,就为该进程复制出一个新的内存页供其使用。

在 QEMU/KVM 中,一个虚拟客户机就是一个 QEMU 进程,因此使用 KSM 也能够实现多个客户机之间的相同内存合并。并且,若是在同一宿主机上的多个客户机运行的是相同的操做系统或应用程序,则客户机之间的相同内存页数量就可能还比较大,这种状况下KSM的做用就更加显著。在KVM环境下使用 KSM ,KSM还容许KVM 请求哪些相同的内存页是能够被共享合并的,因此KSM只会识别并合并哪些不会干扰客户机运行,不会影响宿主机或客户机的安全内存页。可见,在KVM 虚拟化环境中,KSM 可以提升内存的速度和使用效率,具体能够从如下两个方面来理解:

(1)在 KSM 的帮助下,相同的内存页被合并了,减小了客户机的内存使用量,一方面,内存中的内存更容易被保存到CPU 的缓存中;另外一方面,有更多的内存可用于缓存一些磁盘中的数据。所以,无论是内存的缓存命中率,仍是磁盘数据的缓存命中率都会提升,从而提升了 KVM 客户机中操做系统或应用的运行速度;
(2)KSM 是内存过载使用的一种较好的方式。KSM 经过减小每一个客户机实际占用的内存数,就可让多个客户机分配的内存数量之和大于物理内存数量。而对于使用相同的内存量的客户机,在物理内存量不变的状况下,能够在一个宿主机中建立更多客户机,提升了虚拟化客户机部署的密度,提升了物理资源的利用效率。

 

KSM 是在 Linux 内核 2.6中被加入到内核主代码中去的,目前多数流行的 Linux 发行版都已经将 KSM 的支持编译到内核中了,其内核配置文件中有 “CONFIG_KSM=y” 项:

[root@192.168.118.14 ~]#egrep -i ksm /boot/config-3.10.0-327.el7.x86_64 
CONFIG_KSM=y

Linux 系统的内核进程 ksmd 负责扫描后合并进程的相同内存页,从而实现 KSM 功能。root 用户能够经过 "/sys/kernel/mm/ksm/" 目录下的文件来配置和监控 ksmd 这个守护进程。KSM 只会去扫描和试图合并那些应用程序建议为可合并的内存页。

KSM 最初就是为 KVM 虚拟化中的使用而开发的,不过它对非虚拟化的系统依然很是有用。KSM 能够在KVM 虚拟化环境中很是有效的下降内存使用量,在KSM的帮助下,有人在物理内存为 16GB 的机器上,用KVM 成功运行了多达 52 个 1GB 内存的windows xp 客户机。

因为KSM 对 KVM 宿主机中的内存使用有较大的效率和性能的提升,因此通常建议打开 KSM 功能。,但是,因为KSM必须有一个或多个进程去检测和找出哪些内存页是彻底相同能够用于合并的。所以,KSM 让内存使用量下降了,可是 CPU 使用率会有必定程度的升高,也可能会带来隐蔽的性能问题,须要在实际使用环境中进行适当配置 KSM 的使用,以便达到较好的平衡。

KSM对内存合并而节省内存的数量与客户机操做系统及其上运行的应用程序有关,若是宿主机上的客户操做系统及其上的应用程序也相似,节省内存的效果就会很显著,甚至节省超过 50%的内存都有可能的。反之,若是客户机操做系统不一样,且运行的应用程序也大不相同,KSM 节省内存效率很差,可能连 5%都不到。

另外,在使用 KSM 实现内存过载使用时,最好保证系统的交换空间(swap space)足够大,由于 KSM 将不一样客户机的相同内存页合并而减小了内存使用量,可是客户机可能因为须要修改被KSM合并的内存页,从而使这些被修改的内存被从新复制出来占用内存空间,所以可能会致使系统内存不足,这是须要足够的交换空间来保证系统的正常运行。

 

3.1 KSM 操做实践

内核 KSM 守护进程是 ksmd,配置和监控 ksmd 的文件在 "/sys/kernel/mm/ksm/" 目录下:

[root@192.168.118.14 ~]#ll /sys/kernel/mm/ksm/
total 0
-r--r--r--. 1 root root 4096 Jul  9 08:21 full_scans
-rw-r--r--. 1 root root 4096 Jul  9 08:21 merge_across_nodes
-r--r--r--. 1 root root 4096 Jul  9 08:21 pages_shared
-r--r--r--. 1 root root 4096 Jul  9 08:21 pages_sharing
-rw-r--r--. 1 root root 4096 Jul  9 08:21 pages_to_scan
-r--r--r--. 1 root root 4096 Jul  9 08:21 pages_unshared
-r--r--r--. 1 root root 4096 Jul  9 08:21 pages_volatile
-rw-r--r--. 1 root root 4096 Jul  9 08:21 run
-rw-r--r--. 1 root root 4096 Jul  9 08:21 sleep_millisecs

说明:
full_scans:记录已经对全部可合并的内存区域扫描过的次数;
pages_shared:记录着正在使用中的共享内存页的数量;
pages_sharing:记录着有多少数量的内存页正在使用被合并的共享页,不包括合并的内存页自己。这就是实际节省的内存页数量;
pages_unshared:记录了守护进程去检查并试图合并,却发现了并无重复内容而不能被合并的内存页数量;
pages_volatile:记录了由于其内容很容易变化而不被合并的内存页;
pages_to_scan:在KSM进程休眠以前会去扫描的内存数量;
sleep_millisecs:ksmd 进程休眠的时间(单位:毫秒),ksmd 的两次运行之间的间隔;
run:控制 ksmd 进程是否运行的参数,默认值为0,要激活 ksm 必需要设置其参数为 1,设置为0,表示中止运行 ksmd 但保持它已经合并的内存页;设置为1,
   表示立刻运行 ksmd进程;设置为2 表示中止运行 ksmd,并分离已经合并的全部内存页,可是保持已经注册为合并的内存区域给下一次运行使用.

 

经过权限能够看出, 只有 pages_to_scan , sleep_millisecs, run 这 3 个文件对 root 用户是可读可写的,其他 5 个文件都是 只读的,能够向 pages_to_scan 、 sleep_millisecs、 run 这三个文件中写入自定义的值以便控制 ksmd的运行。

例如:

echo 1200 > /sys/kernel/mm/ksm/pages_to_scan  用来调整每次扫描的内存页数量
echo 10 > /sys/kernel/mm/ksm/sleep_millisecs  用来设置ksmd两次运行的时间间隔
echo 1 > /sys/kernel/mm/ksm/run  用来激活ksmd 的运行

 

pages_sharing 的值越大,说明 KSM 节省的内存越多,KSM 效果越好,以下命令计算了节省的内存数量:

[root@mongodb ~]# echo "KSM saved: $(($(cat /sys/kernel/mm/ksm/pages_sharing) * $(getconf PAGESIZE) / 1024 / 1024))MB"
KSM saved: 1159MB

 

在 CentOS 7 系统中,提供了两个服务 ksm 和 ksmtuned 来动态调节 KSM 的运行状况,这两个服务都包含在 qemu-kvm-common 这个 RPM 安装包中。

[root@192.168.118.14 ~]#systemctl status ksm
● ksm.service - Kernel Samepage Merging
   Loaded: loaded (/usr/lib/systemd/system/ksm.service; enabled; vendor preset: enabled)
   Active: active (exited) since Tue 2019-07-09 09:59:40 CST; 21s ago
  Process: 668 ExecStart=/usr/libexec/ksmctl start (code=exited, status=0/SUCCESS)
 Main PID: 668 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/ksm.service

Jul 09 09:59:40 localhost.localdomain systemd[1]: Starting Kernel Samepage Merging...
Jul 09 09:59:40 localhost.localdomain systemd[1]: Started Kernel Samepage Merging.
[root@192.168.118.14 ~]#systemctl status ksmtuned
● ksmtuned.service - Kernel Samepage Merging (KSM) Tuning Daemon
   Loaded: loaded (/usr/lib/systemd/system/ksmtuned.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2019-07-09 09:59:40 CST; 25s ago
  Process: 680 ExecStart=/usr/sbin/ksmtuned (code=exited, status=0/SUCCESS)
 Main PID: 685 (ksmtuned)
   CGroup: /system.slice/ksmtuned.service
           ├─685 /bin/bash /usr/sbin/ksmtuned
           └─686 sleep 60

Jul 09 09:59:40 localhost.localdomain systemd[1]: Starting Kernel Samepage Merging (KSM) Tuning Daemon...
Jul 09 09:59:40 localhost.localdomain systemd[1]: Started Kernel Samepage Merging (KSM) Tuning Daemon.

当 ksm 服务启动时: run 文件为 1

[root@192.168.118.14 ~]#cat /sys/kernel/mm/ksm/run 
1

在 KSM 服务启动后,KSM 可以共享最多达到系统物理内存一半的内存页。而 ksmtuned 服务一直保持循环执行,以调用 ksm 服务的运行,其配置文件的 /etc/ksmtuned.conf ,默认配置以下:

[root@192.168.118.14 ~]#cat /etc/ksmtuned.conf 
# Configuration file for ksmtuned.

# How long ksmtuned should sleep between tuning adjustments
# KSM_MONITOR_INTERVAL=60

# Millisecond sleep between ksm scans for 16Gb server.
# Smaller servers sleep more, bigger sleep less.
# KSM_SLEEP_MSEC=10

# KSM_NPAGES_BOOST=300
# KSM_NPAGES_DECAY=-50
# KSM_NPAGES_MIN=64
# KSM_NPAGES_MAX=1250

# KSM_THRES_COEF=20
# KSM_THRES_CONST=2048

# uncomment the following if you want ksmtuned debug info

# LOGFILE=/var/log/ksmtuned
# DEBUG=1

 

在主机内存为 8 GB 的系统上,使用 Linux 3.10 内核的 CentOS 7 系统做为宿主机,开始将 ksm 和 ksmtuned 服务暂停,"/sys/kernel/mm/ksm/run" 的默认值为 0 ,KSM 不生效,而后启动每一个内存为 1GB 的 4 个 cirros 客户机,再次启动 KSM 和 ksmtuned服务,5分钟后检查系统内存的使用状况以肯定 KSM 效果。脚本及执行以下:

[root@192.168.118.14 ~]#cat test-ksm.sh 
#!/bin/bash
echo "stop ksm"
systemctl stop ksm
systemctl stop ksmtuned
echo "---free -m---"
free -m
for i in {1..3};do
  qemu-img create -f qcow2 -o backing_file="/images/cirros-0.3.5-i386-disk.img" /images/cirros-${i}.qcow2
  echo "starting the No. ${i} guest..."
  qemu-kvm -smp 1 -m 1024m /images/cirros-${i}.qcow2 -daemonize
  sleep 20
done
echo "---free -m---"
sleep 10
free -m
echo "---starting services: ksm and ksmtuned..."
systemctl start ksm
systemctl start ksmtuned

sleep 300

echo "---free -m command output with ksm and ksmtuned running."
free -m

echo "KSM saved: $(($(cat /sys/kernel/mm/ksm/pages_sharing) * $(getconf PAGESIZE) / 1024 / 1024))MB"


*****************执行以下*****************
[root@192.168.118.14 ~]#./test-ksm.sh 
stop ksm
---free -m---
              total        used        free      shared  buff/cache   available
Mem:           7823         115        7565           8         142        7537
Swap:          8063           0        8063
Formatting '/images/cirros-1.qcow2', fmt=qcow2 size=41126400 backing_file='/images/cirros-0.3.5-i386-disk.img' encryption=off cluster_size=65536 lazy_refcounts=off 
starting the No. 1 guest...
VNC server running on `::1:5900'
Formatting '/images/cirros-2.qcow2', fmt=qcow2 size=41126400 backing_file='/images/cirros-0.3.5-i386-disk.img' encryption=off cluster_size=65536 lazy_refcounts=off 
starting the No. 2 guest...
VNC server running on `::1:5901'
Formatting '/images/cirros-3.qcow2', fmt=qcow2 size=41126400 backing_file='/images/cirros-0.3.5-i386-disk.img' encryption=off cluster_size=65536 lazy_refcounts=off 
starting the No. 3 guest...
VNC server running on `::1:5902'
---free -m---
              total        used        free      shared  buff/cache   available
Mem:           7823         368        7266           8         188        7261
Swap:          8063           0        8063
---starting services: ksm and ksmtuned...
---free -m command output with ksm and ksmtuned running.
              total        used        free      shared  buff/cache   available
Mem:           7823         248        7382           8         191        7377
Swap:          8063           0        8063
KSM saved: 121MB

 

以上输出中,从 KSM、ksmtuned 服务开始运行以前和以后的 "free -m" 命令看出 used 从 368 下降到 248,明显节约了系统内存。

相关文章
相关标签/搜索