允许在排队状态下中止实时迁移

https://blueprints.launchpad.net/nova/+spec/abort-live-migration-in-queued-status

此蓝图增加了支持,允许在 queued(排队)状态下中止实时迁移。

问题描述

中止实时迁移的功能是在 microversion 2.24 中添加的 [1],目前仅允许中止处于 running(运行中)状态的迁移。

有一个配置选项 max_concurrent_live_migrations,可用于控制并发实时迁移的最大数量,默认值为 1。当实时迁移请求的数量可能大于最大并发实时迁移配置时,将会有迁移在队列中等待。这些迁移可能会根据队列长度和处理速度,在 queued(排队)状态下停留很长时间。

管理员可能希望由于时间消耗等原因而中止队列中的迁移。在状态变为 running(运行中)之前让管理员等待是不合理的。

用例

由于迁移队列长度和处理速度,迁移可能会在 queued(排队)状态下长时间停滞。管理员可能希望由于时间消耗等原因而中止队列中的迁移。

提议的变更

整个更改将分为两个步骤

步骤 1 - 修复缺少队列的问题

在当前实现中,在计算节点上序列化实时迁移的代码使用 Python semaphore(信号量),信号量的值设置为 CONF.max_concurrent_live_migrations,每个传入的迁移将尝试获取此信号量,如果获取成功,信号量的值将减少 1,迁移的状态将变为 queued(排队)以外的状态。当值减少到 0 时,新的传入迁移将被阻止(迁移状态将为 queued(排队)),直到一些先前的迁移完成(成功、失败或中止)并释放信号量。

根据上述实现,由于实际上没有队列,因此无法中止处于 queued(排队)状态的迁移,因此我们无法控制被信号量阻止的迁移。

此规范将提出一个可以实现上述目标的设计

  • 使用来自 concurrent.futures lib 的 ThreadPoolExecutor(线程池执行器)代替当前 eventlet.spawn_n() + Python Semaphore(信号量)实现。线程池的大小将限制为 CONF.max_concurrent_live_migrations。当实时迁移请求进来时,我们将 _do_live_migration 调用提交到池中,它将返回一个 Future 对象,稍后我们将使用它。如果池已满,新的请求将被阻塞并保持在 queued(排队)状态。

  • 将一个新的 _waiting_live_migration 变量添加到计算节点的 ComputeManager 类中,这将是一个字典,并初始化为空字典。我们将

    1. 记录 migration_uuid 和上一步创建线程时 Future 对象之间的连接,我们将使用 migration_uuid 作为键,Future 对象作为我们的字典中的值。

    2. 如果线程成功获取执行器并进入 _do_live_migration() [2],则首先删除相应的键/值。 这样,我们将拥有类似队列的东西来存储 Futures,并使其能够通过 migration_uuid 获取它们。

步骤 2 - 允许在排队状态下中止实时迁移

在步骤 1 中提出的修改之后,我们将能够获取被 migration_uuid 阻塞的线程,然后我们可以中止它们

  • 首先检查提供的 migration_uuid 是否在 _waiting_live_migration 字典中,如果不在,则它将处于 queued(排队)以外的状态,我们可以切换到今天的流程。

  • 如果提供的 migration_uuid_waiting_live_migration 字典中,则获取相应的 Future 对象并调用 ThreadPoolExecutorcancel() 方法。

  • 如果取消调用成功,我们将对处于 queued(排队)状态的迁移执行回滚和清理。如果提供的 Future 对象当前正在执行,则取消调用将返回 False,这意味着提供的线程不再被阻塞,因此我们可以切换到中止处于 running(运行中)状态的迁移的流程,就像今天一样。

  • DELETE /servers/{id}/migrations/{migration_id} API 添加一个 API microversion(微版本),以允许在 queued(排队)状态下中止实时迁移。如果请求的 microversion 等于或高于新添加的 microversion,API 将在发出 RPC 调用之前检查 instance.host's nova-compute 服务版本,并确保它足够新以支持新的支持,否则,API 仍将返回 400,就像今天一样。

  • rpcapi 接口将被修改为接受迁移对象作为参数,以便我们可以根据目标计算版本和迁移状态来决定是否可以发送 rpc 调用,我们仍然会在 rpc 调用中发送 migration.id。

  • 我们还将在计算管理器关闭时向池中添加清理。这部分将在实现过程中进行试验和错误,因为仍有一些细节需要弄清楚。这里的原则是,我们不希望阻塞服务的关闭,因此我们希望将这些迁移设置为 cancelled(已取消)状态,取消队列 Future,以便池关闭不会阻塞它。cleanup_host 期间的步骤是

    1. 关闭池,这样我们就不会收到新的请求

    2. 对于任何排队的迁移,将迁移状态设置为 cancelled(已取消)

    3. 使用 Future.cancel() 取消 future

    步骤 2 和 3 可能是可以互换的,我们将在实现中找到最佳顺序。

备选方案

数据模型影响

REST API 影响

该提案将向 DELETE /servers/{id}/migrations/{migration_id} API 添加 API microversion(微版本),以允许在 queued(排队)状态下中止实时迁移。当使用大于新添加的 microversion 的 API microversion 的请求时,如果请求的实时迁移状态为 queued(排队)状态,响应将从 HTTP 400 BadRequest 更改为 HTTP 202 Accepted

安全影响

通知影响

其他最终用户影响

Python-novaclient 将被修改以处理新的 microversion(微版本),以允许在 queued(排队)状态下中止实时迁移。

性能影响

其他部署者影响

开发人员影响

升级影响

如果运行实例的计算服务太旧,计算 API 仍然会返回 400,以尝试中止排队状态下的迁移。

实现

负责人

主要负责人

郑振宇

工作项

  • 将计算管理器转换为使用线程/futures 排队迁移

  • 创建一个新的 API microversion(微版本),以允许在 queued(排队)状态下中止实时迁移。

  • 修改 rpcapi 接口以接受迁移对象作为参数,以便我们可以根据目标计算版本和迁移状态来决定是否可以发送 rpc 调用。

  • 修改 python-novaclient 以处理新的 microversion(微版本)。

依赖项

测试

需要新的 in-tree 功能和单元测试。

文档影响

需要有关新的 API microversion(微版本)和使用方法的文档。

参考资料

历史

修订版

发布名称

描述

Rocky

提议