镜像预缓存支持

https://blueprints.launchpad.net/nova/+spec/image-precache-support

Nova 支持在计算节点级别按需缓存镜像以提高性能,但没有提供在发布或维护窗口之前安排该活动的能力。这项长期以来被要求的特性,在考虑边缘计算环境、有限带宽以及大规模快速应用部署时变得更加重要。

问题描述

Nova 中的几个虚拟驱动程序支持缓存基本镜像以提高启动性能。当实例首次从给定镜像启动时,该基本镜像会从 glance 下载、缓存,并复制或 CoW 以创建实际的实例根磁盘。后续从同一镜像启动的实例可以使用缓存的镜像副本,而不是再次从 Glance 下载。这种行为具有以下好处

  • 减少 Glance 服务器的负载

  • 减少网络利用率

  • 减少第二次及后续实例的启动延迟

后者对于必须在特定时间窗口内执行新的应用程序发布的情况,或者预期响应不断变化的工作负载而快速进行扩展操作的情况尤其重要。具体来说,在升级窗口打开之前,或者在负载意外激增之前,确保新镜像已缓存在所有相关计算节点上非常重要。

此外,在计算节点可能位于网络带宽有限的环境(例如许多边缘计算环境)的远程位置的情况下,在利用率低或维护窗口期间将新的基本镜像推送到这些节点非常重要,这样镜像下载过程就不会在正常操作期间消耗大量带宽。

由于 Nova 没有提供从外部启动此过程的方法,操作员目前被迫通过变通方法来解决问题。我们已知正在使用的一些变通方法包括

  • 手动在每个计算节点上预启动一次性实例,以在部署实际实例之前填充缓存

  • 直接将镜像复制到计算节点上的缓存目录中(通过非带内方式)

  • 修改 Nova 代码本身以提供此功能

  • 使用共享存储卷作为镜像缓存(已知存在问题)

  • 使用完全不同的临时后端,例如 ceph,从而完全规避该问题(但需要更大的投资)

用例

  • 作为具有远程计算节点云的运营商,我希望能够在维护窗口期间预缓存镜像,以避免启动新实例并按需拉取基本镜像所涉及的网络峰值。

  • 作为使用支持频繁批量重新部署应用程序的云的用户,我希望能够在我的发布窗口之前在计算节点上预缓存新镜像,以将我的应用程序停机时间限制为仅重新生成或重建实例所需的时间。

提议的变更

此功能已被多次提出和请求,但由于各种原因未能获得团队的认可。因此,本规范提出一个最小可行性的初始实现,该实现解决了预缓存的需求,但未提供特定的可见性、报告、调度或其他高级功能。

最初,我们将向 Nova 添加一种机制,允许(具有足够权限)的用户请求将一组镜像缓存在包含在主机聚合中的计算节点集合上。此活动将委托给(超级)conductor worker,它将

  • 验证提供的镜像(是否存在和可访问性,以避免要求大量计算执行不可能的事情)

  • 查找给定聚合中的主机列表

  • 按 cell 整理主机

  • 迭代这些主机,发出 RPC 请求以启动操作

如果我们通过 RPC cast 发送所有这些请求以异步处理,肯定会对镜像服务造成 DDoS。适当的节流可以通过许多方式完成,并且很容易成为后续规范的主题。在此初始版本中,我们将引入一个可配置的并行限制,这将导致 conductor 并行联系那么多计算节点以触发其下载,并使用长期运行的 RPC 调用功能等待完成。

镜像将在每个计算节点上使用 virt 驱动程序上的新方法进行缓存,该方法在实现时将重用镜像启动期间已经使用的镜像下载例程。通过此机制缓存的镜像将受到与因实例启动而按需下载的镜像相同的过期和清除规则的约束。后续调用缓存已驻留的镜像应重置缓存中的过期计时器(如果适用)。对于使用 imagecache 模块的现有驱动程序,我们只需要 *touch* 它们来更新它们的 mtime

备选方案

另一种选择是始终什么都不做。过去已经多次提出和要求过这一点,人们目前正在没有它地生活和/或自行解决限制。

另一种选择是采取类似的方法,但放弃增量性质。我们可以实现一个更大的 API,具有任务和进度报告、调度(镜像 X 应该缓存 Y 小时等)和其他功能,这些功能是先前请求的一部分。不这样做的原因是为了避免因打开的众多兔子洞而永远无法完成此操作。请参阅参考部分,了解以前未完成的尝试的完整列表。

数据模型影响

在此初始迭代中没有。将来,可能需要跟踪每个计算节点的镜像和状态,这需要在数据库中进行一些核算。

REST API 影响

从技术上讲,将此功能放在 Nova 的镜像 API 下可能更有意义。但是,目前该 API 已被标记为已弃用。由于这主要基于聚合模型,因此本规范建议将其作为聚合上的操作添加。

os-aggregates

将为聚合添加一个用于缓存管理的 images 的新路由。

  • POST /os-aggregates/{aggregate_id}/images (成功时返回 202)

    {
      "cache": [
        {"id": "a26887c6-c47b-4654-abb5-dfadf7d3f803"},
        {"id": "4d8c3732-a248-40ed-bebc-539a6ffd25c0"}
      ]
    }
    

由于我们试图提供一个最小可行性的初始实现,因此请求的结构定义为将来可以添加其他信息。这可能包括其他每镜像信息(例如优先级、TTL 等)或每请求信息,例如并行性、下载速率等。

安全影响

显然,允许任何用户启动大规模的数据移动会带来一些固有的风险。由于本规范建议基于聚合,因此用户可能需要已经具有至少列出主机聚合的能力才能将其提供给缓存 API。定义具有该能力的用户的策略旋钮将默认为现有的具有管理主机聚合能力的用户。

通知影响

如果没有基于 API 的每计算进度报告,发出关于镜像下载开始和完成的通知可能会有所帮助。这将允许操作员监控该过程。

其他最终用户影响

客户端显然需要获得访问此 API 的能力。普通用户将完全不受影响,除非他们可能注意到改进的启动性能。

性能影响

此更改的主要目标是在预缓存镜像后提高实例启动的性能。当然,在预缓存操作期间,镜像服务、协调任务的 conductor worker 以及执行工作的计算节点将承受一些额外的负载。计算节点上的实际镜像下载操作将使用当前在镜像启动期间使用的相同代码路径。

其他部署者影响

部署者需要确定应允许哪些用户访问此缓存 API(如果有),并相应地修改策略。

开发人员影响

这将需要 conductor、compute 上的新 RPC 方法,以及对 virt 驱动程序的相应调用。目前,libvirthypervvmwareapi 驱动程序使用 imagecache。将为 libvirt 驱动程序提供初始支持,但由于其他两个驱动程序重用了 imagecache 模块,因此应该很容易实现。

升级影响

由于此初始版本的函数是尽力而为的,没有真正的报告或保证镜像已缓存且在任何截止日期之前,因此升级影响很小。如果计算 RPC API 固定到低于发出此调用的版本,则不会联系任何计算节点来预缓存镜像。

如果缓存调用针对正在运行尚未(或永远不会)能够参与的 virt 驱动程序的计算节点,则基础 virt 驱动程序将发出警告日志消息。

实现

负责人

主要负责人

danms

功能联络人

功能联络人

danms

工作项

  • 扩展基础 virt 驱动程序以包含一个 cache_image() 方法,该方法接受一个镜像 ID。默认行为是 NotImplemented 异常。

  • 在 libvirt 驱动程序中实现 cache_image() 方法

  • 将新的 RPC 调用添加到计算管理器,该管理器委托给 virt 驱动程序。如果引发 NotImplemented,则会记录一条关于缺乏支持的警告消息。

  • 将新的 RPC 调用添加到 conductor 管理器,以查找、按 cell 整理并调用相关计算节点。

  • 添加一个新的 REST API 调用,允许用户发出此请求。

  • 添加客户端实现以发出此调用。

依赖项

openstackclient、novaclient 和 nova 上的补丁将相互依赖。

测试

由于此实施的初始阶段未对正在运行的部署进行任何外部可见的更改,因此使用 tempest 进行测试必须依赖于一些晦涩的东西,例如启动延迟时间来确定成功。因此,将添加功能测试以确保通过新的调用填充镜像缓存,并且后续实例启动不会联系镜像服务以执行下载。

文档影响

此功能需要对操作员在管理指南中进行文档记录,当然还需要 api-ref 更改。

参考资料

历史

修订版

发布名称

描述

Ussuri

引入