文档目录架构 · 18 篇

快照产物与挂载模型

说明快照产物的布局与发布流程、清单内容、校验与完整性、层级、快照身份、重放契约、宿主挂载和内存共享。

译自microsoft/nvx · doc/design/5.4-snapshot-artifact-and-attachment-model.md。技术细节以英文原文为准。

架构文档 > 5. VM 生命周期与状态

5.4.1 产物布局与发布

图 5.4 展示了一个已发布快照中的文件,图 5.5 展示这些文件是如何发布的。

snapshot/
|-- manifest.bin
|-- state.bin
|-- memory.bin
`-- scratch.img    # paired scratch only

图 5.4。 快照目录布局。

图 5.5。 快照发布。

节点与含义:

  • 已停止的 VM 状态(Stopped VM state)
  • 精确捕获的基础 RAM 文件句柄(Exact captured base-RAM file handle)
  • 可选的精确暂存盘文件句柄(Optional exact scratch file handle)
  • 唯一私有同级暂存目录(Unique private sibling staging directory),自上而下包含:
    • state.bin:写入并刷新。
    • memory.bin:精确捕获的基础 RAM,来自自动生成或调用方提供的后备文件。
    • scratch.img:复制、校验长度并刷新。
    • manifest.bin:记录契约与长度,在自动 RAM 硬链接之前写入并刷新。
  • 刷新暂存目录(Flush staging directory)
  • 同父目录内的无覆盖重命名(发布提交点)(No-replace same-parent rename, publication commit point)
  • 最终快照目录(Final snapshot directory)
  • 刷新父目录(Flush parent directory)
  • 移除自己拥有的暂存目录(Remove owned staging directory)

转换关系(→ 表示流入与写入,⇢ 表示带标注的虚线条件):

源节点 关系 目标节点
已停止的 VM 状态 → state.bin(写入并刷新)
精确捕获的基础 RAM 文件句柄 → memory.bin(精确捕获的基础 RAM)
可选的精确暂存盘文件句柄 ⇢(配对策略) scratch.img(复制、校验长度并刷新)
state.bin → manifest.bin
memory.bin → manifest.bin
scratch.img → manifest.bin
manifest.bin → 刷新暂存目录
刷新暂存目录 → 同父目录内的无覆盖重命名(发布提交点)
同父目录内的无覆盖重命名(发布提交点) → 最终快照目录
最终快照目录 → 刷新父目录
唯一私有同级暂存目录 ⇢(提交之前失败) 移除自己拥有的暂存目录

发布会把每个产物写入并刷新到一个权限受限的唯一私有同级暂存目录,刷新该目录,用一次同父目录内的无覆盖重命名提交它,然后刷新父目录。提交之前的失败会移除暂存目录,而已存在的目的地绝不会被删除或替换。

由 VMM 创建的 RAM 后备文件无需复制即可发布。一旦它的共享映射、状态和清单都已持久化,就把那个精确打开的后备文件硬链接到暂存目录中,并重新打开该链接,与源的文件身份和长度进行校验。在文件系统无法链接该句柄的情况下,以及对于调用方提供的后备文件,发布改为复制内存,并在文件系统支持时克隆区段(extent)。在自动 RAM 硬链接提交之后,源 VM 即为终止状态。暂存链接创建之后的失败,只有在私有暂存目录已被移除且其父目录已被刷新之后才是可安全回滚的;否则,VMM 会终止该源,而不是用一个可写的产物别名来恢复它。

5.4.2 清单

清单在以下方面具有权威性:

  • 机器配置文件与 ABI 版本。
  • 源 hypervisor 与架构。
  • 捕获的 RAM 区间与文件偏移,以及任何不可变 RAM 容量、128 MiB 内存块大小和规范扩展区间。
  • 处理器拓扑、处理器数量以及每一个 APIC 身份。
  • 生效命令行及其摘要。
  • 精确的设备顺序、稳定 ID、状态单元名称、MMIO 与 PMIO 区间、中断、传输、特性掩码和队列上限。
  • 时间契约:声明的 TSC 与 LAPIC 速率、速率容差、捕获锚点、宿主时钟类型、宿主与启动身份、代次计数器以及 Q。
  • CPU 配置文件记录:CPU 配置文件的 ID、摘要和规范文档、生效 CPUID,以及捕获宿主的 CPU 签名。
  • 必需的宿主挂载及其策略。
  • 块的角色、访问方式、几何、层身份、暂存盘策略和配对暂存盘的实例化。
  • 快照层级、克隆或续跑策略,以及已消耗的配置区段。
  • 状态产物与内存产物的精确长度,以及配对暂存盘的精确长度与身份。

5.4.3 校验与完整性

快照路径与重复字段都是有界的。恢复会在客户机执行之前拒绝被截断、超长、格式错误、类型错误、路径逃逸、符号链接、不兼容、缺失、多余或顺序错乱的状态。清单不存储任何校验和,VMM 也绝不读取产物或块来校验其内容,因此对其中任何一项的等长改动都超出了校验契约的范围:完整性依赖于宿主访问控制,以及存储所有者保持每个块的存储代次不可变;而经认证的导出或传输属于本地产物格式之外的事。配对暂存盘必须与被捕获的文件系统状态相匹配,因此恢复会在结构上以及按精确大小和存储代次对它进行检查。

恢复只打开一次快照目录,并相对于该目录句柄解析每个产物,包括续跑声明。它会一直持有目录与产物句柄直到拆除。Windows 宿主以只读共享方式打开产物,拒绝重解析点,并在创建写时复制映射前后检查文件身份和文件末尾,从而阻止写入、截断、删除和重命名。Linux 宿主保留精确的描述符,打开时不跟随符号链接,并在移交给工作线程之前检测元数据变化,因此路径名替换不会产生影响。除此之外的内容不可变性取决于宿主访问控制。

5.4.4 层级

如表 5.3 所示,带沙箱块的快照会声明三个生命周期层级之一。

表 5.3. 快照层级。

层级 恢复策略 暂存盘 已消耗的配置 共享范围
platform 克隆 全新 仅不变量 受信任的平台构建
workload-start 克隆 配对 不变量、镜像绑定和沙箱 租户范围内的热工作负载或运行时
instance-checkpoint 续跑(resume) 配对 不变量、镜像绑定和沙箱 一个活动实例,带一个已被认领的续接

层级元数据要求有沙箱块;无块快照不声明层级。已保存的、由宿主拥有的层级标记必须与清单一致。平台下层具有未绑定的身份,而较晚的层级会绑定每一个已消耗的层。已消耗区段集合记录了客户机在捕获时已经消耗了哪些配置。

平台这个切入点把内核和客户机代理的初始化从后续启动中去掉。工作负载启动快照还会去掉运行时初始化,但它包含工作负载内存,并且往往包含缓存的镜像数据和机密。只读层文件仍然是外部挂载,但从其中读到的字节可能出现在被捕获的内存中。配对暂存盘是快照目录中的一个产物,而不是对调用方原始可写文件的引用。

共享范围是部署要求,而不是 VMM 的租户授权特性。快照控制器强制执行层级组合、层绑定、暂存盘配对以及一次性的续跑声明。宿主产物访问控制、模板来源信息以及捕获前值得信赖的客户机,共同决定跨租户发布是否被允许。

5.4.5 快照身份

快照按角色、访问模式、精确长度和块几何来绑定每一个已消耗的块,此外还有一个由调用方提供、非零的存储代次,所有被绑定的块都共享它。捕获和恢复都不会读取某个块来标识它:捕获记录该代次,恢复则要求提供它并检查结构字段。因此,存储所有者要为这些字节作保,并且必须保持该代次不可变且绑定到精确的文件。该代次不是字节摘要,VMM 也不会对它进行认证。

已封存的快照是不可变的。克隆会创建一个独立的可写后代,而续跑则以原子方式认领该快照并把它的续接转移到一个活动实例中,之后它就不再是一个可用的快照。不存在可变的快照状态。

5.4.6 重放契约

恢复会重放被捕获的客户机状态,因此捕获遵循一份明确的契约:绝不捕获活动的外部连接或无法被安全复用的其他状态,绝不重复不可逆的副作用,并且在接受工作之前修复运行时的随机性。内核熵再播种无法重置运行时自身的随机数生成器、缓存或连接,因此工作负载启动快照需要一个运行时的恢复后钩子。可克隆的热切入点必须是单线程的,或者把每个对等线程都挡在一个由运行时拥有的屏障之后,直到修复完成。实例检查点是一个续接,而工作负载启动快照是一个可克隆的起点;两者都不是对任意请求的透明检查点。

5.4.7 宿主挂载

如表 5.4 所示,机器状态包含的是客户机可见的进度,而不是原生的进程资源,并且每个外部资源都有一个稳定的 ID 和一份声明式的重建策略。

表 5.4. 宿主挂载的重建。

资源 保存的内容 恢复时重建或提供的对象
字节通道 待处理的 RX 与 TX 字节 宿主端点、一个新鲜的代次 ID,以及一个可选的恢复包
启动控制台 队列进度、已暂存的 RX、部分 TX、端点身份和重连策略 在其捕获端点上的一个合格监听者,或同类的一个经批准的新鲜端点、一个必需的客户端连接,或一个由调用方提供的继承终端
控制控制台 挂载身份、broker 策略和有界的 broker 状态(不含排队记录、宿主输出或接收信用);绝不包含能力或对端身份 一个经批准的同用户本地端点,可能位于一个新位置,并配以新鲜的能力;broker 以一个新的实例和纪元重启
网络 静态身份、队列与数据包进度、网络配置文件和策略摘要 一个策略匹配的全新进程内端点;已发布的客户机监听者和宿主转发会被拒绝
宿主文件系统 FUSE 命名空间、句柄、cookie、根与对象身份、访问模式和路径策略,或者明确的休眠状态 一个具有相同规范路径、目标、模式和策略的全新导出;一个休眠槽位可以保持未挂载,或绑定一个新的目录导出
沙箱块 队列与设备状态、角色、访问方式、几何、层身份、暂存盘策略和配对暂存盘的实例化 匹配的只读层,外加以供克隆使用的私有副本或写时复制暂存盘、在独占续跑认领之后的直接暂存盘,或一个具有相同几何的新暂存文件
就绪端点 无 供一次恢复使用的可选一次性端点

挂载解析在任何处理器启动之前进行。调用方提供的挂载必须复现保存下来的身份,只有一个例外:合格的监听者可以替换它的端点,同时保留其稳定 ID、挂载种类与后端种类、重连策略、必需标志、长度和超时。权限缺失、端点绑定失败、出站策略改变、文件系统对象被替换,或挂载种类错误,都会显式地让恢复失败。可复用克隆的编排器应提供全新的私有启动控制台端点和控制端点,从而让彼此独立或并发的恢复绝不与已终止的源发生冲突。

5.4.8 内存共享

私有的写时复制恢复可以防止某个 VM 的写入修改可复用的产物。它并不保证在映射同一文件的各个 VM 之间干净的物理页一定不共享,而且在捕获前丢弃客户机页缓存本身并不能消除共享的宿主物理页或缓存侧信道。因此,写隔离与页共享隔离是两个彼此独立的属性。