虚拟化能通过启用工作负载合并来提高效率。使虚拟机密度最大化的同时维持良好的性能,这确实是个挑战:
- 工作负载对资源,如 CPU、内存、网络带宽和存储访问的利用随时间而变化;如果您能够根据需要动态分配这些资源,您就能在超量使用 的情况下获得更大的密度。
- 优化的资源资源管理还取决于系统配置和硬件设置这些因素。
开发出一套整合这两个因素的管理策略的方法之一是用策略语言编写一组规则。您可以根据您独特的情况调整您的策略,并有效平衡整合和性能目标。
本文将探索与超量使用相关一些挑战,并推荐一个策略驱动的管理工具,它能帮助您应付这些挑战。此工具部署在典型的 KVM 环境中,并管理两组不同的工作负载。本文评估了这些实践的结果,加以总结,并推荐了一些额外的工作内容和深入的研究课题。
彻底的 KVM 内存超量使用调查应该从 Linux 内存管理器本身开始。由于它是构建在虚拟内存概念之上,Linux 原本的设计中就包含了内存超量使用技术。
进程所请求的内存页在实际使用时才会分配。使用 Linux 页面缓存,多个进程可以通过共享页面访问文件来节省内存;当内存用尽时,系统通过把不常用的页面交换到磁盘来释放内存。虽然不是非常完美,但这些技术能造成分配内存量和实际使用量之间的实际差异。
由于 KVM 虚拟机是常规进程,可以使用标准内存转换技术。但与常规进程不同的是,KVM 客户包含一套内嵌的操作系统,它以两种关键方式影响内存超量使用。 KVM 客户比常规进程具有更大的内存超量使用潜力。这是由于利用率波动导致的最小和最大客户内存需求之间的差异造成的。
可变性的资本化的核心任务是虚拟化,但这并不容易。当主机管理分配给 KVM 客户的内存时,客户内核也同时在管理相同的内存。如果主机与客户之间缺乏某种形式的协作,主机和客户内存管理器都无法做出缓存和交换相关的决策,这将会导致内存的低效使用和性能下降。
Linux 提供了额外的机制用来解决由虚拟化引起的内存超量使用。
- 内存膨胀(Memory ballooning)是一种主机指示合作客户释放一些已分配内存以用于其他用途的技术。此技术能帮助将内存压力重新从主机转移到客户上。
- Kernel Same-page Merging (KSM) 使用一个内核线程扫描之前确认的内存范围内是否有一样的页面,将其合并并释放副本。运行大量相同虚拟机的系统从这种内存共享方式中获益最大。
- 其他资源管理特性,例如 Cgroups 有内存超量使用方面的应用程序,它能在虚拟机之间动态分配资源。
这些机制都为管理超量使用的内存提供了有效的框架,但它们都有一个共同的限制:必须由外部实体来配置和调优。无法进行自动配置,这是因为虚拟栈的单个组件没有足够信息来做出调优决策。
例如,某个 qemu 进程就无法知道主机是否用完内存以及能从客户处增加多少内存而不会对性能,以至于产生不利影响。只有联合考虑主机和客户的管理策略和实时信息才能做出决策。
为了解决 KSM 的挑战,编写了一个名为 ksmtuned
的后台程序来动态管理与共享潜能和内存需求相关的可调参数。由于 ksmtuned
单独管理一个机制,因此无法作为综合解决方案的一部分。
使用任何超量使用机制都会从根本上影响主机和客户内存管理系统的运行。因此,同时使用多个机制可能会造成二次影响。图 1 演示了内存膨胀和 KSM 之间的相互影响。
图 1. 内存膨胀对 KSM 的影响
本例中,增加的膨胀压力削弱了 KSM 共享页面的能力。客户膨胀驱动器选择要膨胀的页面而不考虑页面是否已经被占用。膨胀已占用的页面是一个错误,因为它剥夺了客户资源而未实际节省内存。为了能达到最大的效率,必须要预测和管理这些相互作用。
您可以部署基于 KVM 的虚拟化,进行各种配置,使用可满足不同目标的架构。积极的虚拟机联合方法需要权衡性能。两者之间的适当平衡视情况而定。
内存超量使用可能增加所有其他系统资源的需求。内存缓存压力会造成磁盘或网络 I/O 增加,页面回收活动增加会让客户消耗更多的 CPU 周期。
您可以通过使用一个可完成此任务的新后台程序来应对挑战:Memory Overcommitment Manager (MOM)。
MOM (Memory Overcommitment Manager) 后台程序如图 2 所示。
图 2. Memory Overcommitment Manager
MOM 提供了一个灵活的框架用于主机和客户统计数据收集,一个策略引擎和一些控制点用于膨胀和 KSM。使用 MOM,管理员可以构建对应于实时情况的超量使用策略,并可动态调整系统的可调参数,以实现更高级别的内存超量使用。
MOM 使用 libvirt 来维护运行在主机上的虚拟机列表。关于主机和客户的数据会定期收集。数据可能会来自多处(/proc
主机接口、libvirt API、virtio 串口 或与客户的网络连接)。数据一旦收集,将由策略引擎整理,供进一步使用。(Virtio 是一种网络和磁盘设备标准,在此标准中,只有客户的设备驱动器 “知道” 它运行在虚拟环境中,从而能与管理程序协作,让客户获得高性能网络和磁盘操作。总之,使用 Virtio 可获得半虚拟化的最佳性能收益。
策略引擎本质上是一个可理解用简单的策略语言编写的程序的小解释器。MOM 将定期使用收集的数据评估用户提供的策略。此策略可能触发配置变更,如客户内存膨胀增大或 KSM 扫描速度变化。
随着时间推移,这方面技术的发展,MOM 框架可以扩展,收集其他数据源的数据并控制新的内存超量使用机制。
为了评估 MOM 和它在管理超量使用内存方面的效果,我们看两个虚拟化工作负载:
- 在第一个工作负载中,虚拟机配置为更具描述的访问模式使用不同数量的虚拟内存。
- 第二个工作负载使用一个 LAMP 基准,每个虚拟机作为一个独立的 MediaWiki 实例。
对于每个工作负载,都要评估控制内存膨胀和 KSM 的 MOM 策略。为了避免主机交换,每个客户的内存膨胀都根据主机和客户内存压力动态调整。与 ksmtuned
的算法一样,KSM 也是根据内存压力和可用内存数量进行调整的。
Memknobs 工作负载场景使用一个名为 Memknobs 的简单程序,它通过以挑战内核内存回收算法的模式来分配和接收匿名内存页,从而制造出内存压力。Memknobs 分配一个固定大小的缓冲区,循环遍历缓冲区页面,写到每一页上。每次迭代都用逐渐增长的缓冲区大小重复调用 Memknobs,客户可以模拟一个有内存限制而无 I/O 组件的工作负载。要在主机上超量使用内存,我们将 Memknobs 部署在 32 台虚拟机上, 每个实例都以独一的模式使用内存。
对于 Cloudy 工作负载场景,我们创建一个带有 I/O 组件的实际工作负载,它使用一个名为 Cloudy 的开放套件。Cloudy 是很容易设置的 LAMP 基准,它可以衡量虚拟化扩展性,并可以显示资源环境的效果。多个虚拟机配置为 MediaWiki 服务器。每个 wiki 加载时都有 Wikipedia 的页面和随机生成的图片数据。
内含的 JMeter 测试计划会执行所有的实例和测量吞吐量以及响应时间。配置测试计划来产生状态稳定的工作负载,或者通过调整多个虚拟机组之间的负载来产生变化。负载的数量 和类型可以通过改变请求速率、并发用户数,以及随机生成的 wiki 图片大小来改变。PHP 加速器可以将 CPU 消耗降到忽略不计的程度。此工作负载在访问虚拟机镜像存储设备时可以产生数量可观的 I/O,并且对可用带宽数量相当敏感。
我们的内存膨胀策略的思路是防止主机交换,把内存压力转移到其他客户上。由于主机缺乏客户页访问信息,从而不能在选择交换页面时合理地使用 LRU 算法。更进一步,客户操作系统具有最多的关于工作负载的内存使用的信息,应该能做出最好的页面替换决策。
该策略依靠内存膨胀来维护一个随时可释放的主机内存池。我们将可释放内存定义为 /proc/meminfo
中报告的 MemFree
、Buffers
和 Cache
之和。当该池收缩到总内存 20% 以下,内存膨胀就会启动。根据主机内存压力级别将压力分配到客户。首先回收空闲内存,从而具有更多未用内存的客户膨胀最多。有了足够的膨胀压力,客户将驱逐出缓存页并开始交换。一旦压力减弱,膨胀就会缩减,将内存返回给客户。
我们的 KSM 调优算法设计为匹配 ksmtuned
。首先,根据我们设置为主机总内存 20% 的空闲内存阈值做出是否启用内核线程的决策。只有主机满足了全部 两个条件,才允许 KSM 运行:
- 空闲内存超过阈值,并且
- 总内存较少的空闲内存阈值超过分配给所有虚拟机的内存总数。
这些条件会分别测试主机是否处于内存压力之下,虚拟化是否要负责。 在不需要时关闭 ksmd
可节省 CPU 周期。
当启用 ksmd
后,其运行会根据总内存大小和内存大小调优。扫描之间的休眠时间会根据主机内存大小调整。对于 16GB 主机,默认是 10 秒。机器越大,休眠越短,越小休眠越长。每次扫描的页面数会根据空闲内存而增加或减少。如果空闲内存小于空闲内存阈值,扫描速率会增加 300 页。否则下降 50。扫描页面数不能超过 64 至 1,250 的范围。
我们的试验在 IBM BladeCenter® HS22 上进行。系统有 16 个逻辑 CPU,带有 EPT 支持和 48GB RAM。对于不断增长的存储容量和带宽,虚拟机镜像放在外部 NFS 设备上,通过私有 10 千兆 Ethernet LAN 连接。我们使用 Memknobs 和 Cloudy 工作负载场景评估 MOM 策略的有效性。为了衡量每个场景中的性能影响,在 MOM 策略启动和关闭时都进行一小时的测试。
对于这个试验,我们提供了 32 个虚拟机,每个有 2GB RAM 和 1 个 VCPU。我们校准 Memknobs 内存负载,如图 3 所示,将主机置于足够的内存压力之下,以产生定期交换活动。通过试验,我们能够产生给出所需主机行为的模式。
图 3. Memknobs 内存访问模式
Memknobs 程序追踪每次迭代时它所能接触到的页面数。吞吐量值是以每秒接触到的内存千兆数为单位报告的。为了能够比较不同试验,我们通过计算每个客户的平均吞吐量并 将 32 个值相加来得出一个总的平均吞吐量分数。表 1 比较了使用不同 Memory Overcommitment Manager 策略的分数。
表 1. MOM 策略结果:Memknobs 总平均吞吐量
MOM 策略 | 结果 |
---|---|
无 | 4331.1 |
仅 KSM | 4322.6 |
KSM 和膨胀 | 5399.5 |
这些结果显示,使用内存膨胀造成吞吐量增长近 20%。尽管 KSM 在共享页面方面对工作负载非常有效,但它不对性能增长负责。图 4 比较了 Memknobs 在内存膨胀情况下和没有的情况下运行的交换活动。
图 4. Memknobs 交换对比
启用 MOM 策略后,交换活动有效集中在客户,交换操作的总数下降了一半。
为了使 Cloudy 大小适合我们的环境,我们配置了 32 个虚拟机 MediaWiki 实例。此工作负载私用的内存比 Memknobs 少。为了保证客户内存受限,仅给每个 VM 分配 1GB RAM。为了弥补虚拟机使用量减少,我们保留了 15,714 个大页面 — 有效将主机的可用内存降到 16GB。
JMeter 测试计划配置为平均每秒每台虚拟机发送 16 个请求。这在系统未超量使用时可以产生没有资源瓶颈的中等负载。JMeter 会记录它发出的每个请求的统计数据。我们以服务质量(QOS)为度量,有 95% 的请求延时,以毫秒为单位。平均实例吞吐量是所有完成的请求数(以千字节为单位)除以参与客户数。
表 2 显示的是 KSM 和内存膨胀 MOM 策略在启用和禁用下的 QOS 和吞吐量。
表 2. Cloudy QOS 和吞吐量
VM | MOM 策略 | QoS | 吞吐量 |
---|---|---|---|
1 | 关 | 1669 | 710007 |
32 | 关 | 3240 | 774555 |
32 | 开 | 3231 | 764762 |
单个 VM 上的运行结果演示了不受限的主机上的性能。此数据的观察结果是能动态提升 Memknobs 性能的 MOM 策略对 Cloudy 没有效果。此工作负载中的内存利用主要是由文件 I/O 引起,而不是匿名内存,几乎没观察到交换活动。相反,内存超量使用把压力推给主机和客户页面缓存,增加 I/O,这是因为系统视图将工作负载限制在更小的内存中(见图 5)。
图 5. 单个客户上内存膨胀对 I/O 的影响
尽管有效限制了内存,使用大页面保留减少可用内存却可能对客户内存管理算法产生一点小影响。在以后,这个试验将会放在机器上用 16GB 物理内存来评估最真实场景下的系统。
通过研究这些不同的工作负载的对比结果,可以得出一个明确的结论:在超量使用内存时,要考虑系统和负载的所有方面。没有万能管理策略。
在初期阶段,这项工作就有望提升 KVM 资源超量使用的状态,并且计划和进行多项提升。
目前,主机和客户之间没有标准的通讯方式。目前的方法(如主机到客户网络通讯)取决于主机和每个客户的手工配置和设置,这种方式取决于操作系 统类型和版本、数据中心网络配置以及虚拟机设备模型。我们的目标是通过将支持多数据传输,包括 virtio 串口和模拟串口的通讯机制集成到 qemu 中来简化这个问题。此通道的客户端可由开源、多平台 qemu 客户工具包支持。这样的机制将提升 MOM 收集统计数据的能力,并可广泛用于如复制/粘贴和管理任务这样的特性。
如以上演示,超量使用策略在某些情况下有用,某些情况下却可能造成不利影响。为了能安全部署,策略一定不能影响性能。应当通过添加防范措施来提升 MOM 策略,当他们不能产生预期结果时,应该能回滚管理操作。
现在,KVM 有一种可有效协作的共享 CPU 机制。当客户 CPU 执行 hlt
指令,它自愿产生 CPU 时间给其他客户。如果相同客户驱动的协议存在并产生内存自愿,内存超量使用的性能影响就会降低。
当社区开发可提升 KVM 超量使用的新特性时,对这些特性的支持也集成到了 MOM 基础架构中。例如,我们计划启用对基于 cgroups 的 RSS 限制以加强膨胀指令,并保护系统远离非合作或恶意客户。
资源超量使用对于虚拟化收益最大化以及研究开发都至关重要。随着 Linux 虚拟化的发展,对于超量使用最佳实践也是如此。一个整体的、策略驱动的管理超量使用的方法是最大限度提升效率和推动提升的最佳方法。