RFC-0201:回收客机虚拟机内存 | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 允许主机使用之前分配并稍后释放的客机虚拟机内存 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2022-12-15 |
审核日期(年-月-日) | 2022-12-01 |
摘要
允许主机回收由来宾使用的内存。
设计初衷
在来宾中运行需要大量内存的应用并在主机中启动需要大量内存的应用可能会导致 OOM,即使来宾内存不再使用也是如此。
原因有二。
- 我们目前不允许主机自动从客户机获取内存。
- 我们不支持让访客主动告知主机“这是未使用的内存页列表,如有需要,请随意使用”。
用户体验历程示例
- 启动 termina 或 debian 访客
- 在客户机中启动内存占用量大的应用
- 退出占用大量内存的访客应用
- 在宿主机中启动内存占用量大的应用
- 观察主机发生 OOM 的情况 💥
背景
操作系统启动时,会询问硬件(在来宾的情况下为 Hypervisor)有多少物理内存。如果主机告诉来宾它有 4 GiB 的 RAM,来宾就会知道它可以分配大约 100 万个 4 KiB 页面。
具体方法是在虚拟机操作系统视为物理地址(称为“虚拟机物理地址”)的地址与实际物理地址(称为“主机物理地址”)之间引入一级映射。请注意,第一级地址转换是指在客机虚拟内存地址和客机物理地址之间进行映射。换句话说,客机虚拟地址首先由硬件转换为客机物理地址(硬件使用由客机操作系统管理的页面表进行转换),然后再转换为主机物理地址(后续转换由 Hypervisor 管理的页面表控制)。
当访问未映射的客机虚拟地址到客机物理地址时,客机会处理自己的页面故障。Hypervisor 会处理客户机物理地址到主机物理地址的转换的页面故障。
我们使用的是分页内存,这意味着当 Hypervisor 向客户机提供 X GiB 的 RAM 时,它不会预先分配任何内存,而是仅在实际需要这些页面时才会分配。在本例中,“必需”表示访客尝试访问该网页。从 Hypervisor 的角度来看,分配的物理内存页属于客户机,不能用于主机进程。
因此,客户机最终可能会有大量未使用的已分配物理内存页面,而主机可能内存不足,无法运行自己的进程。
下面,我们将介绍 2 种向主机提供客机内存的方法:
- 在客机中膨胀 virtio 气球
- 在 virtio 气球中使用空闲页面报告
Virtio-balloon
主机可以通过配置目标气球大小,指示客机 virtio-balloon 驱动程序将气球inflate
到特定大小。膨胀气球意味着客机将预留所需数量的内存页,并将分配的内存页的客机物理地址报告回主机。从此时起,主机可以取消提交已报告的内存页,并使用用于回滚已报告内存的物理内存。
如果 virtio-balloon 协商了 VIRTIO_BALLOON_F_DEFLATE_ON_OOM,则客机可以随时重新开始使用内存。请参阅 Virtio 规范 5.5.6.1。目前,我们启用了 VIRTIO_BALLOON_F_DEFLATE_ON_OOM。
主机可以通过缩减气球的目标大小,允许客机重复使用气球中的页面。如果配置的气球大小小于气球中的实际页面数量,则客户机可能会重复使用之前提供给气球的页面。如果该来宾容器想要再次使用内存,则会 deflate
气球,让主机知道该来宾容器日后将使用一系列物理来宾地址。在压缩后,当客户机访问已从气球中移除的页面时,它会遇到客户机物理到主机物理页面故障,而 Hypervisor 会为客户机分配新的物理内存页面以供使用。
如需详细了解 virtio-balloon 核心功能,请参阅 Virtio Balloon 幻灯片和 Virtio Balloon 视频
免费网页报告
2020 年,virtio-ballon 新增了一项名为“Free Page Reporting”(免费页面报告)的新功能。
可用页面报告功能为客户机添加了一种向主机报告可用内存页面的方法。为此,客户端会向空闲页面报告中添加大小为 4 MiB(Linux 实现常量)的空闲页面,并将报告发送给主机。在托管者确认收到报告之前,访客保证不会重复使用任何免费页面。
当主机收到空闲页面报告时,它会取消提交内存页面,使其可供主机应用使用,并将确认报告发回给客户机。此时,访客可以重复使用之前已免费和确认的页面。如果客户机决定重复使用该页面,主机会检测到客户机物理页面到主机物理页面故障,并分配新的物理页面来满足客户机请求。
如需了解详情,请参阅 Free page reporting: by Alexander Duyck ( Intel ). Slide 10。
利益相关方
教员:
- cpu@google.com
Reviewers:
- abdulla@google.com
- dahastin@google.com
- tjdetwiler@google.com
咨询了:
- cwd@google.com
社交:
此 RFC 已通过虚拟化团队的审核。我们与 cwd@google.com 讨论了此方法,对方正在为 ChromeOS 解决一个类似但更大的问题。
设计
目标
- 在客机中运行应用后,为主机回收内存。
- 最大限度地降低内存回收对客户机和主机的性能影响。
非目标
- 在多个客户机之间平衡大量内存用量。
- 当客户机和主机争用内存时,动态确定应用的优先级。
- 支持 Fuchsia 访客的内存回收。
成功标准
- Fuchsia 在“动机”部分中所述的用户体验历程中不会发生 OOM。
- 主机可用内存大致会恢复到在客机中运行占用大量内存的应用之前的水平。
- 在内存回收之前和之后,访客可以继续运行需要大量内存的应用。
- 除非主机处于低内存压力下,否则访客页面缓存不会受到影响。
- 至少有一个客机正在运行时,主机 OOM 的数量显著减少。
解决方法
- 使用 virtio_balloon 中的空闲页面报告功能回收空闲内存以供宿主机使用。
- 在主机内存压力事件为“LOW”和“CRITICAL”时膨胀气球,以清除客机页面缓存并回收已分片的内存页。
- 概念验证已确认,空闲页面报告确实会按预期回收内存。
实现
使用免费的网页报告
我们将使用空闲页面报告功能向主机报告并回收所有空闲内存。
全部是指有序的 PAGE_REPORTING_MIN_ORDER 或更高级别的任何内容(在 Linux 内核中定义为 4 MiB)。
使用空闲页面报告会在接下来的 30 秒内回收大部分内存。报告的可用页面大小为 2 MiB 或 4 MiB,预计会出现一定程度的内存碎片化。在访客端,系统会分阶段报告非付费网页,以最大限度地减少对性能的影响。
Linux-5.15 会以 2 MiB 和 4 MiB 的块报告 30 秒内的大部分可用内存。
空闲页面报告不会驱逐 Linux 页面缓存,如果客户机正在运行 I/O 密集型工作负载,这可能会成为一个问题。如需了解 Linux 中的页面缓存,请参阅 Linux 页面缓存基础知识。
当我们的 Linux 客机映像开始使用 MGLRU 时,这种情况可能会发生变化。请参阅 MGLRU 的“缺点、替代方案和未知情况”部分。
不随意清除页面缓存是件好事,因为它是有原因存在的。只有在主机实际需要时,才应从客户机页面缓存中获取内存。这意味着,我们需要提供一种方法,以便在主机面临内存压力时回收用于页面缓存的访客内存。
在主机内存压力下膨胀来宾气球
第二项更改是使用内存压力提供程序在主机内存达到“警告”和“严重”级别时膨胀气球。
充气气球可实现两个目标:
- 驱逐客机页面缓存。如果客机执行大量文件 IO 并填满页面缓存,这非常重要。
- 回收大部分已分片的内存页,因为气球膨胀是按 4KiB 粒度完成的,而可用页面报告使用的是 4MiB。
膨胀量将与可用客机内存成正比。在主机内存发生 WARNING 和 CRITICAL 事件时,气球将膨胀到可用客户机内存的 90%。我们必须在发生 WARNING 和 CRITICAL 事件时进行膨胀,以防可用内存从 NORMAL 急剧下降到 CRITICAL。当主机内存压力恢复为“正常”时,气球将收缩到 0%。
我们希望避免在主机面临内存压力时不断膨胀和收缩气球。气球膨胀会对房客和房东造成性能开销。此外,据 Intel 称,不断调整气球大小会导致许多 TLB 关闭。
为防止气球大小来回波动,我们将气球膨胀操作的速率限制为每 X 秒 1 次膨胀。在 teamfood 测试期间配置的 X。初始值为 1 分钟。可能会有更多超时,例如,如果主机在内存压力警告状态下停留时间过长,则会超时以收缩气球。您可以根据 Teamfood 测试遥测数据添加其他超时。
性能
当用户在客户机中运行内存需求较大的应用时,实现内存回收可提升主机内存性能。主机将有更多可用内存可供使用,而无需诉诸内存压缩和其他 CPU 开销较高的内存获取方式,而客机则有可回收的可用内存。
在 Linux 实现中,空闲页面报告操作会在 30 秒内错开,以减少对访客的性能影响。我们预计内存密集型客机工作负载的性能会受到 1%-2% 的影响。请参阅“免费网页”报告基准测试。
在主机内存不足时膨胀气球可能会给主机和客户机增加额外的负载。
我们需要在启用和不启用内存回收的情况下,衡量主机在内存压力下运行时发生的客机“TLB 终止”中断的数量。
基准:
- Linux 压力工具
- 某个图形基准测试,例如 Uningine
要捕获的指标
- 基准测试报告的用于检测性能回归的一般指标
- 基准测试前后,客机和主机中的可用内存
- 在来宾中发生 TLB 终止中断
安全注意事项
在取消提交操作期间,系统会将已回收的空闲页面设为 0,就像气球膨胀一样。这样可以防止访客信息泄露给房东和其他访客。
测试
大部分工作将由单元测试和 2 项集成测试完成。其中一个集成测试将涵盖空闲页面报告内存回收,另一个将涵盖客机页面缓存与气球膨胀的交互。
我们将手动测试动机部分中所述的用户体验历程。用户体验历程依赖于访客启动,因此不具封闭性。如果我们有自动化端到端虚拟化测试,则可以扩展该测试以涵盖此场景。我们认为,依赖于为此 RFC 构建自动化端到端虚拟化测试是不切实际的。
缺点、替代方案和未知情况
多代 LRU 框架
多代 LRU 框架(也称为 MGLRU)是 Linux 内核的内存改进功能。Linux 中当前的页面回收在 CPU 使用方面成本过高,并且在选择要驱逐的内容时经常做出错误的选择。MGLRU 旨在做出比当前 Linux 内核页面回收代码更好的选择,并更高效地做出这些选择。Google 工程师的数据显示,冷启动时间最多缩短了 16%,同时减少了低内存终止次数;ChromeOS 浏览器中的内存不足终止次数减少了 59% 以上,低内存标签页舍弃次数减少了 96%;服务器端的结果也非常喜人。
如需了解详情,请参阅 PATCH v14 00/14 多代 LRU 框架。
我们目前使用的 Termina 5.15 不包含 MGLRU 补丁。MGLRU 在上游版本中不可用。Termina 内核开发者正在等待 MGLRU 被上游接受,以便向 Termina 5.15 进行回移
MGLRU API 可用于驱动免费网页报告逻辑。值得研究使用 MGLRU API 来提升 Linux 内核中的空闲页面报告性能。如果成功,可以提议将其合并到上游。这将是对 Linux 内核中现有空闲页面报告解决方案的优化。
允许主机回收客机内存时,无需依赖于 MGLRU。
持续调整气泡大小的替代方案
最初建议执行内存回收的方式,因此得名为内存守护程序。
这是 ChromeOS 目前使用的做法。但也存在一些缺点
- 需要选择轮询间隔。
- Intel 报告了,即使是小幅的气球调整也会产生性能开销。请参阅持续调整气球大小会导致许多 TLB 关闭
- 为了使此功能正常运行,气球必须始终膨胀到占用约 90% 的客机内存。
- 来宾应用可以快速分配,并在下一个轮询间隔之前被 OOM 守护程序终止
ChromeOS 方法
ChromeOS 目前正在开发响应式 virtio-balloon 的下一迭代。简而言之,该想法是在客机和宿主机中使用低内存终止守护程序来调整气球大小,而不是终止应用。我们还计划使用 MGLRU 来指导气球大小调整逻辑。
ChromeOS 要解决的是一个更难、更不同的问题:
- ChromeOS 有多个客户机和主机,它们都在争夺内存
- ChromeOS 和所有客户机都具有可连接的 MGLRU 和低内存终止守护程序守护程序。
- 为所有工作负载选择合适的气球大小是一项难题。
- 我们必须定义一组启发词语来指导气球膨胀/收缩逻辑
- 请务必获取来自设备群的数据,以便构建启发词语并分析其有效性。
- 更重要的是,如果您使用 LMKD 触发气球膨胀/收缩,则必须快速调整气球大小,否则 OOM 终止程序将在气球膨胀/收缩时终止应用
Fuchsia 虚拟化没有可用于收集统计信息的大量设备。我们要解决的问题要简单得多。Fuchsia 没有可连接的 OOM 终止程序。
Fuchsia 主机确实允许同时运行多个客户机(Termina、Debian、Fuchsia)。目前,这不是主要用例,通常用户和测试会运行单个访客。当我们开始使用更强大的硬件时,这种情况可能会有所改变。如果访客未使用所有可用内存,则建议的解决方案适用于多个超额订阅的访客。例如,空闲的 Debian 客户机和处于活动状态的 Termina 客户机。
如果我们必须支持多个客户机,而这些客户机会尝试使用所有可用内存,问题空间会变得更大。确定哪个访客申请或哪位访客更重要,应该是产品政策的范畴。我们应专注于向产品提供合适的工具,但在平台级别,我们不想对如何处理低内存做出规定。
我们将采用更简单、更可预测的解决方案来解决当前问题,同时添加数据收集功能来分析 OOM,并确定是否需要添加更复杂的启发词语。
使用 DAX 和 virtio-fs 共享主机和来宾页面缓存
借助 DAX 映射,客户机可以直接访问主机缓存中的文件内容,从而避免客户机和主机之间出现重复。为 DAX 添加 virtio-fs 支持、启用页面缓存共享,以及在内存压力下添加页面缓存舍弃,是清除客机页面缓存的 virtio 气球膨胀替代解决方案。由于气球膨胀,精细的页面缓存控制比全面页面缓存驱逐更好。我们可以舍弃旧页面缓存,同时保留新页面缓存,以缓解内存压力,而不会过多影响主机/客户机性能。
在先技术和参考文档
- 免费的网页报告
- 适用于 Linux 的 Windows 子系统 2 中的内存回收
- 补丁 v14 00/14 多代 LRU 框架
- Linux 中的 Virtio mem
- 气球对页面缓存施加压力
- PAGE_REPORTING_MIN_ORDER
- 持续调整气球大小会导致许多 TLB 关闭
- “Virtio Balloon”幻灯片
- “Virtio Balloon”视频
- Linux 页面缓存基础知识
- 虚拟内存
- 免费网页报告基准
- DAX 映射
- memorypressure 提供程序