1 内存虚拟化简介

QEMU-KVM 提供内存的虚拟化,从虚拟机角度看其自身拥有的内存就是真实的物理内存。实际上,虚拟机是 host 上的一个 qemu 进程,在为虚拟机指定内存时,host 上并没有分配该内存给虚拟机(qemu 进程),而是需要使用内存时,由 qemu-kvm 分配内存给它。
 
这里了解 QEMU-KVM 内存虚拟化机制。

2 内存虚拟化配置

传统的内存虚拟化通过影子页表实现,但是影子页表实现复杂,而且内存开销很大,每个 qemu 进程都需要维护自己的影子页表。
基于硬件支持的内存虚拟化技术能较好的解决影子页表带来的问题,Intel CPU 提供 EPT 技术支持内存虚拟化,AMD 提供 NPT 技术支持内存虚拟化。
 
在 host 上查看硬件是否支持内存虚拟化:
[demo@lianhua ~]$ cat /proc/cpuinfo | grep "model name"
model name : Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz [demo@lianhua ~]$ cat /proc/cpuinfo | grep -E "ept|vpid"
fpu_exception : yes
flags : ... vmx smx aes tpr_shadow vnmi flexpriority ept vpid fsgsbase
可以看出,host 上使用的是 Intel 的 CPU,该 CPU 已经支持了 ept 和 vpid。
 
kvm_intel 模块在加载时会默认开启 ept 和 vpid,从而 KVM 可以使用它们:
[demo@lianhua ~]$ cat /sys/module/kvm_intel/parameters/ept
Y
[demo@lianhua ~]$ cat /sys/module/kvm_intel/parameters/vpid
Y
 
在创建虚拟机时,通过 qemu-kvm 的 -m 选项指定虚拟机的内存:
[root@lianhua ~]# free -h
total used free shared buff/cache available
Mem: 251G 85G 11G 56M 155G 159G
Swap: 0B 0B 0B [root@lianhua ~]# /usr/libexec/qemu-kvm -m 5G -smp 2 demo.qcow2 -monitor stdio
QEMU 2.6.0 monitor - type 'help' for more information
(qemu) VNC server running on '::1;5900'
(qemu) [root@lianhua ~]# free -h
total used free shared buff/cache available
Mem: 251G 85G 11G 56M 155G 159G
Swap: 0B 0B 0B
 
如上所示,指定虚拟机的内存为 5G,在创建虚拟机之后, host 上并没有分配 5G 内存给虚拟机。

3 内存虚拟化特性

类似 vCPU 虚拟化特性,内存虚拟化也有几大特性:

3.1 内存过载(over-commit)

顾名思义,内存过载即 host 上总的虚拟机内存可以大于 host 内存。在 host 上不同虚拟机可能实现不同的功能,不同功能使用的内存不尽相同,一般不会保证内存 100% 被使用到。因此,可以对内存进行过载分配。
 
内存过载分配主要有三种方式:
  • 内存交换(swapping):通过 host 上的 swap 交换分区分配过载的内存。
  • 内存气球(ballooning):通过半虚拟化的 ballooning 机制实现内存过载分配。
  • 页共享(page sharing):通过 KSM(Kernel Samepage Merging) 合并多个相同内存页实现内存过载分配。

3.1.1 内存交换

内存交换是最常用的内存过载分配方式。它是在虚拟机内存需要过载分配时,将 swap 交换分区的内存分配给虚拟机,从而实现内存的过载分配。
 
使用内存交换进行内存过载分配时,用户不需要显示的指定其它配置,但是要保证 swap 交换分区有足够多的空间可供分配。比如,host 上有 10 台虚拟机,每台虚拟机指定的内存为 1G,而 host 上的物理内存有 6G,那么,不算操作系统自己占用内存的情况下,还需要至少 4G 的内存才能实现虚拟机内存的过载,这至少 4G 的内存就要从 swap 交换分区中分配。
 
注意:swap 交换分区是使用磁盘存储内存数据的分区,相比于直接使用内存条存储数据要慢的多。如果虚拟机对读写性能有要求的话,那么,在使用内存交换进行内存过载分配之前还需要评估性能是否受影响。

3.1.2 内存气球

3.1.2.1 内存气球简介

内存气球是通过半虚拟化机制的 ballooning 方式实现的内存过载分配。如下图所示:
 
内存气球是在虚拟机内部引入气球的概念,气球内的内存不能被虚拟机使用。当 hypervisor 请求扩大内存时,虚拟机内部的气球就会膨胀,内存页就会释放。当虚拟机需要扩大内存时,虚拟机内部的气球就会缩小,可用的内存增多。引入内存气球的机制可以动态调整虚拟机的内存。
 
ballooning 方式是在半虚拟化机制下工作的(半虚拟化原理可看这里),在 host 上配置的 virtio 后端驱动是 virtio_balloon,在虚拟机中配置的 virtio 前端驱动是 virtio-pci:
[root@lianhua ~]# find /lib/modules/3.10.0-514.6.2.el7.x86_64/ -name virtio*.ko
...
/lib/modules/3.10.0-514.6.2.el7.x86_64/kernel/drivers/virtio/virtio_balloon.ko [root@vm:/sys/module]
# ls /sys/module/virtio*
/sys/module/virtio_blk:
parameters uevent /sys/module/virtio_net:
parameters uevent /sys/module/virtio_pci:
drivers parameters uevent version
(驱动加载位置因操作系统及配置而异,并不是所有机器的驱动模块都在这个路径下)
 
结合 virtio 的驱动及内存气球工作原理,再次介绍内存气球的工作流程:
1) hypervisor 发送请求给虚拟机,请求虚拟机释放内存。
2) 虚拟机的 virtio-pci 驱动接收到该请求,并且使虚拟机内部的内存气球膨胀。
3) 内存气球膨胀之后,虚拟机可用的内存减少,虚拟机通知 hypervisor 内存已释放。
4) hypervisor 将释放的内存分配到需要内存的地方。

3.1.2.2 内存气球配置

配置内存气球,首先需要在 host 上加载 virtio_ballon 模块。然后,通过 qemu-kvm 的 -device 选项指定虚拟机的内存驱动为 virtio-balloon-pci:
[root@lianhua hxia]# /usr/libexec/qemu-kvm -enable-kvm -smp 2 -m 2G -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x9 -msg timestamp=on  demo.qcow2 -monitor stdio
QEMU 2.6.0 monitor - type 'help' for more information
(qemu) VNC server running on '::1;5900'
 
如上所示,指定虚拟机的内存为 2G,且内存分配方式为 virtio ballooning 分配,balloon 设备的 pci 号为 00:09:0。
 
进入创建的虚拟机,查看 pci 编号及 balloon 设备所使用的驱动:
[root@vm:/home/robot]
# lspci
...
00:09.0 Unclassified device [00ff]: Red Hat, Inc. Virtio memory balloon [root@vm:/sys/module]
# lspci -s 00:09.0 -vvv
00:09.0 Unclassified device [00ff]: Red Hat, Inc. Virtio memory balloon
Subsystem: Red Hat, Inc. Device 0005
Physical Slot: 9
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 10
Region 0: I/O ports at c0c0 [size=32]
Region 4: Memory at fe010000 (64-bit, prefetchable) [size=16K]
Capabilities: [84] Vendor Specific Information: VirtIO: <unknown>
BAR=0 offset=00000000 size=00000000
Capabilities: [70] Vendor Specific Information: VirtIO: Notify
BAR=4 offset=00003000 size=00001000 multiplier=00000004
Capabilities: [60] Vendor Specific Information: VirtIO: DeviceCfg
BAR=4 offset=00002000 size=00001000
Capabilities: [50] Vendor Specific Information: VirtIO: ISR
BAR=4 offset=00001000 size=00001000
Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg
BAR=4 offset=00000000 size=00001000
Kernel driver in use: virtio-pci # balloon 所用的驱动为 virtio-pci
 
除了 qemu-kvm 指定 balloon 设备创建虚拟机的方式外,还可以在 libvirt 的 XML 文件中指定 balloon 设备来创建虚拟机:
<memballoon model='virtio'>
<stats period='10'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
</memballoon>

3.1.2.3 内存气球测试

内存气球配置好以后,进入 qemu 的 monitor 通过执行 balloon 命令手动分配虚拟机的内存(注意 balloon 机制都是通过调用命令行的方式调整虚拟机的内存的,不是内核自发完成的):
[root@lianhua hxia]# /usr/libexec/qemu-kvm -enable-kvm -smp 2 -m 512 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x9 -msg timestamp=on  demo.qcow2 -monitor stdio
QEMU 2.6.0 monitor - type 'help' for more information
(qemu) VNC server running on '::1;5900' (qemu) info balloon
balloon: actual=512
(qemu) balloon 256
(qemu) info balloon
balloon: actual=256
(qemu) balloon 512
(qemu) info balloon
balloon: actual=512
(qemu) balloon 666
(qemu) info balloon
balloon: actual=512
 
如上所示,在 monitor 中通过调用 balloon 命令可以动态调节虚拟机内存大小,在虚拟机中查看内存确实随之而变化。另一方面可以看出,当试图调整 balloon 到超过内存上限 512M 时,实际的内存大小还是 512M,balloon 并没有变化。

3.1.3 页共享

3.1.3.1 页共享简介

页共享是基于 KSM 实现的内存过载分配方式。KSM(Kernel Samepage Merging)内核同页合并会合并内存中的相同内存页,减少内存使用量,从而实现内存过载分配。
应用程序会标记可合并的内存页,KSM 扫描到这些可合并内存页,然后对其进行合并,通常合并是没有风险的。如果应用程序需要修改合并的内存页,则内核会通过“写时复制(copy-on-write,cow)”技术复制一份内存页,然后对复制的内存页进行改写,从而保证了原内存页的安全。
 
RedHat 系列系统默认安装了 ksm 和 ksmtuned 服务程序,使用 ps 命令查看 host 上是否运行 ksm 和 ksmtuned:
[root@lianhua home]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.3 (Maipo) [root@lianhua home]# ps -elf | grep ksm | grep -v grep
1 S root 306 2 0 85 5 - 0 ksm_sc Apr30 ? 01:47:01 [ksmd]
1 S root 1158 1 0 80 0 - 29694 wait Apr30 ? 00:09:34 /bin/bash /usr/sbin/ksmtuned
 
可见,确实安装了 ksm 和 ksmtuned 服务程序,并且程序的进程正在“运行”中。其中,ksm 是主要的合并相同内存页的服务程序,ksmtuned 是对 ksm 的参数配置进行微调的服务程序,因为 ksm 的配置一旦修改了,系统默认不会再去修改它的值,这样对于扫描,合并内存页不够灵活。而 ksmtuned 可以实时动态调节 ksm 的行为。
 
ksmtuned 的配置参数有:
[root@lianhua home]# 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
(看这里了解 ksmtuned 配置参数)

3.1.2.2 页共享配置

使用 qemu-kvm 创建虚拟机时,可指定 -machine 选项的 mem-merge 开关控制内存页共享,mem-merge 为 on 即表示打开内存页共享,off 即表示关闭内存页共享:
[root@lianhua qemu-kvm]# /usr/libexec/qemu-kvm -m 500M -smp 2 lianhua.raw --machine mem-merge=on -monitor stdio
WARNING: Image format was not specified for 'lianhua.raw' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.
QEMU 2.6.0 monitor - type 'help' for more information
(qemu) VNC server running on '::1;5900' (qemu)
 
在 /sys/kernel/mm/ksm/ 目录下查看 ksm 合并的内存页文件:
[root@lianhua home]# ll /sys/kernel/mm/ksm/
total 0
-r--r--r--. 1 root root 4096 Jul 31 13:06 full_scans
-rw-r--r--. 1 root root 4096 Jul 31 13:06 max_page_sharing
-rw-r--r--. 1 root root 4096 Jul 31 13:06 merge_across_nodes
-r--r--r--. 1 root root 4096 Jul 11 17:37 pages_shared
-r--r--r--. 1 root root 4096 Jul 11 17:37 pages_sharing
-rw-r--r--. 1 root root 4096 Jul 12 00:46 pages_to_scan
-r--r--r--. 1 root root 4096 Jul 31 13:06 pages_unshared
-r--r--r--. 1 root root 4096 Jul 31 13:06 pages_volatile
-rw-r--r--. 1 root root 4096 Aug 2 01:05 run
-rw-r--r--. 1 root root 4096 Jul 12 00:46 sleep_millisecs
-r--r--r--. 1 root root 4096 Jul 31 13:06 stable_node_chains
-rw-r--r--. 1 root root 4096 Jul 31 13:06 stable_node_chains_prune_millisecs
-r--r--r--. 1 root root 4096 Jul 31 13:06 stable_node_dups [root@lianhua home]# cat /sys/kernel/mm/ksm/run
0
 
主要文件有:
  • merge_across_nodes:是否允许跨 NUMA 节点合并相同内存页。
  • pages_shared:标记已经在用的内存页数量。
  • pages_sharing:标记合并的内存页数量。
  • pages_to_scan:标记 ksmd 休眠之前扫描的内存页数量。
  • run:标记 ksm 是否运行,有多个标志位,标志位 0 表示停止运行 ksmd 进程但保存已合并的内存页;1 表示运行 ksmd 进程,2 表示停止 ksmd 进程。
 
从上述文件可知,pages_sharing 除以 pages size 即为共享的内存页大小。
 
在 host 上创建 2 个虚拟机,且都打开内存页共享,查看 host 上共享的内存页大小:
[root@lianhua home]# echo "$(( $(cat /sys/kernel/mm/ksm/pages_sharing) * $(getconf PAGESIZE) / 1024 / 1024))MB"
5MB

3.2 内存热插拔

内存虚拟化的另一个特性是内存热插拔,看这里了解内存热插拔特性。
 
 
 

KVM 核心功能:内存虚拟化的更多相关文章

  1. KVM 介绍(2):CPU 和内存虚拟化

    学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...

  2. KVM 内存虚拟化

    内存虚拟化的概念     除了 CPU 虚拟化,另一个关键是内存虚拟化,通过内存虚拟化共享物理系统内存,动态分配给虚拟机.虚拟机的内存虚拟化很象现在的操作系统支持的虚拟内存方式,应用程序看到邻近的内存 ...

  3. KVM(二)CPU 和内存虚拟化

    1. 为什么需要 CPU 虚拟化 X86 操作系统是设计在直接运行在裸硬件设备上的,因此它们自动认为它们完全占有计算机硬件.x86 架构提供四个特权级别给操作系统和应用程序来访问硬件. Ring 是指 ...

  4. [原] KVM 虚拟化原理探究(4)— 内存虚拟化

    KVM 虚拟化原理探究(4)- 内存虚拟化 标签(空格分隔): KVM 内存虚拟化简介 前一章介绍了CPU虚拟化的内容,这一章介绍一下KVM的内存虚拟化原理.可以说内存是除了CPU外最重要的组件,Gu ...

  5. 2017.4.28 KVM 内存虚拟化及其实现

    概述 KVM(Kernel Virtual Machine) , 作为开源的内核虚拟机,越来越受到 IBM,Redhat,HP,Intel 等各大公司的大力支持,基于 KVM 的开源虚拟化生态系统也日 ...

  6. qemu-kvm内存虚拟化1

    2017-04-18 记得很早之前分析过KVM内部内存虚拟化的原理,仅仅知道KVM管理一个个slot并以此为基础转换GPA到HVA,却忽略了qemu端最初内存的申请,而今有时间借助于qemu源码分析下 ...

  7. [ kvm ] 学习笔记 3:KVM 基础功能详解

    1. 构建 KVM 环境 KVM 从诞生开始就需要硬件虚拟化的支持,KVM 必需的硬件虚拟化扩展分别是:Intel 的虚拟化技术(Intel VT)和 AMD 的 AMD-V 技术.首先处理器(CPU ...

  8. kvm简介及创建虚拟化安装(1)

    kvm虚拟化介绍 一.虚拟化分类 1.虚拟化,是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机.在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立 ...

  9. Linux学习-核心编译的前处理与核心功能选择

    硬件环境检视与核心功能要求 根据自己的需求来确定编译的选项 保持干净原始码: make mrproper 我们还得要处理一下核心原始码底下的残留文件才行!假设我们是第一次 编译, 但是我们不清楚到底下 ...

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

    1. 半虚拟化驱动 1.1 virtio 概述 KVM 是必须使用硬件虚拟化辅助技术(如 Intel VT-x .AMD-V)的 Hypervisor,在CPU 运行效率方面有硬件支持,其效率是比较高 ...

随机推荐

  1. vue-test ------class绑定

    <template> <p :class="{'active':isActive}">Class样式绑定</p> <p :class=&q ...

  2. 多维数组、Arrays类、稀疏数组、冒泡排序

    多维数组 多维数组可以看成是数组的数组 比如二维数组就是一个特殊的一堆数组 其中每个元素就是一个数组. 二维数组: int a[][] = new int[2][5]; 解析:二维数组a可以看成一个两 ...

  3. 劫持 PE 文件:搜索空间缝隙并插入ShellCode

    因近期项目需要弄一款注入型的程序,但多次尝试后发现传统的API都会被安全软件拦截,比如 CreateRemoteThread.SetWindowHookEx.APC.GetThreadContext. ...

  4. Unity3d_Rewired官方文档翻译:概念(一):InputManager、Players、Actions

    仅翻译了官方文档中的Essentials(要点).Concepts(概念)两部分,这是文档中最重要的部分,理解了这两部分的内容应该足以让你将Rewired运用到你的项目中,之后再去阅读文档的其他部分也 ...

  5. [Python急救站]学生管理系统链接数据库

    相信很多人在初学Python的时候,经常最后作业就是完成一个学生管理系统,但是我们来做一个完美的学生管理系统,并且将数据储存到数据库里. 我们先看看我们的数据库怎么设置. 首先呢,我选择用的是SQL ...

  6. [Python急救站]回文数的判断

    回文数判断:回文数是指这个数颠倒后,与原数一致,如32223.12221等. 第一个程序是由用户输入,并判断是否是回文数. a = eval(input("请输入一个五位数")) ...

  7. Linux系统快速入门(完整版)

    LINUX基础知识 I.Linux概述 linux是啥? 一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和Unix的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的Un ...

  8. 华为云应用服务网格最佳实践之从Spring Cloud 到 Istio

    摘要:在全球首届社区峰会IstioCon 2021中,华为云应用服务网格首席架构师张超盟发表了<Best practice:from Spring Cloud to Istio>主题演讲, ...

  9. 鲲鹏BoostKit虚拟化使能套件,让数据加密更安全

    摘要:借助华为鲲鹏BoostKit虚拟化使能套件(简称鲲鹏BoostKit虚拟化),可加速迈向云计算之旅.本次KAE加速引擎让数据加密更安全直播将介绍鲲鹏BoostKit加速库全景,基于BoostKi ...

  10. SAST + SCA: 结合使用安全升级

    据 SAP 称,当今85%的安全攻击针对的是软件应用程序,因此一些列应用程序安全测试工具也应运而生.为了避免这些恶意攻击,企业通常使用应用程序安全测试工具来去缓解和解决安全风险,而不同的工具对应的使用 ...