处理下线 Cell

https://blueprints.launchpad.net/nova/+spec/handling-down-cell

本规范旨在解决支持 Nova 的一些基本操作(例如在 Cell 下线时列出实例和服务)所需的行为变更。

问题描述

目前在 Nova 中,当一个 Cell 下线时(例如,如果无法访问 Cell 数据库),基本功能(如 nova listnova service-list)将无法工作,并返回 API 错误消息。然而,单个 Cell 下线不应阻止这些操作对最终用户和操作员有效。另一个问题是,在创建 VM 期间计算配额时,不会考虑下线 Cell 的资源,并且 nova boot 操作被允许进入已启动的 Cell。这可能导致在启动时针对特定项目报告不正确的配额,这在下线 Cell 恢复时可能会产生影响。

用例

本规范要解决的具体用例包括

  1. nova list 即使在 Cell 下线时也应能工作。这可以分为两个用例

    1. 用户在下线 Cell 中没有实例:预期行为是所有操作都应像正常一样工作。如果使用正确的配置选项,这已通过 智能服务器列表 修复。

    2. 用户在下线 Cell 中有实例:这需要优雅地处理,可以分为两个阶段

      1. 我们跳过下线 Cell,并返回来自可用 Cell 的结果,而不是返回 500 错误,这已通过 弹性服务器列表 修复。

      2. 我们不是跳过下线 Cell,而是在现有的 API 响应基础上进行构建(修改),以返回一个简约的结构。此问题将在本规范中修复。

  2. nova show 也应为下线 Cell 中的实例返回一个简约的结构,类似于 nova list

  3. nova service-list 即使在 Cell 下线时也应能工作。解决方案可以分为两个阶段

    1. 我们跳过下线 Cell,并最终显示来自其他 Cell 的所有服务,就像在 cells_v1 设置中一样。这已通过 弹性服务列表 修复。

    2. 我们优雅地处理下线 Cell。这将通过本规范通过创建一个简约的结构来修复。

  4. nova boot 如果请求项目在下线 Cell 中有任何正在运行的 VM,则不应成功,直到通过 使用 Placement 的配额 实现一个与全 Cell 迭代无关的配额计算解决方案。

提议的变更

本规范建议在 nova_api.instance_mappings 表中添加一个新的 queued_for_delete 列,如在 都柏林 PTG 中的 Cell 摘要 中讨论的那样。此列的类型为布尔值,默认情况下为 False,并在相应实例删除(正常/本地/软删除)时设置为 True。在软删除的情况下,如果实例被恢复,则该列的值将再次设置为 False。相应的 queued_for_delete 字段将添加到 InstanceMapping 对象中。

从下线 Cell 列出实例和服务将从 scatter-gather 工具返回一个 did_not_respond_sentinel 对象。使用此响应,我们可以知道一个 Cell 是否下线,并相应地修改列表命令,为来自下线 Cell 的记录以以下方式工作

  1. nova list 应从 API DB 中可用的信息返回一个简约的结构,其中包括

    1. created_at、instance_uuid 和 project_id 来自 instance_mapping 表。

    2. 实例状态将为“UNKNOWN”,这将是表明此记录是部分记录的主要指示。

    3. 其余字段键将缺失。

    有关在使用过滤器、标记、排序和分页时运行此命令的更多信息,请参阅 边缘情况 部分。

  2. nova show 应从 API DB 中可用的信息返回一个简约的结构,类似于 nova list。如果 GET /servers/{id} 无法访问 Cell 数据库,我们可以查看 instance_mapping 和 request_spec 表中的实例详细信息,其中包括

    1. instance_uuid、created_at 和 project_id 来自 instance_mapping 表。

    2. 实例状态将为“UNKNOWN”,这将是表明此记录是部分记录的主要指示。

    3. user_id、flavor、image 和 availability_zone 来自 request_spec 表。

    4. power_state 设置为 NOSTATE。

    5. 其余字段键将缺失。

  3. nova service-list 应从 API DB 中可用的信息返回一个简约的结构,其中包括

    1. host 和 binary 来自 host_mapping 表,用于计算服务。

    2. 其余字段键将缺失。

    请注意,如果 cell0 下线,控制器服务将不会被列出。

  4. nova boot 如果请求项目在下线 Cell 中有正在运行的 VM,则不应成功。因此,如果 scatter-gather 工具在计算配额时返回 did_not_respond_sentinel,我们必须检查该项目是否在 instance_mapping 表中在下线 Cell 中有正在运行的实例,并在有正在运行的实例时阻止启动请求。然而,如果单个 Cell 下线,阻止用户在多个 Cell 中拥有 VM 创建 VM 可能不是理想的。因此,可以添加一个新的策略规则 os_compute_api:servers:create:cell_down,默认值为 rule:admin_api,通过该规则可以控制在项目在下线 Cell 中有实例时创建实例的能力,从而在用户/管理员之间进行控制。使用此方法,部署可以以他们想要的方式配置其设置。

为了使第一个、第二个和第四个操作在 Cell 下线时有效,我们需要在 API DB 中有关实例是否处于 SOFT_DELETED/DELETED 状态的信息,以便将正在运行的实例与已删除的实例区分开,这就是为什么我们添加新的列 queued_for_delete 的原因。

为了防止客户端抱怨缺失的键,我们需要一个新的微版本来接受上述最小结构中的服务器,这些服务器与已启动 Cell 中的服务器的完整结构位于同一个列表中。将来,我们可以使用缓存机制来填充下线 Cell 实例的信息。

请注意,所有其他非列表操作(例如创建和删除)将无法对下线 Cell 中的服务器进行操作,因为如果无法访问 Cell 数据库,则无法明确地执行任何操作。它们将继续像当前场景一样返回 500 错误。

边缘情况

  • 过滤器:如果用户使用过滤器列出服务器,则将跳过下线 Cell 的结果,并且不会提供简约的结构,因为如果缺少过滤器键的值,则无法验证下线 Cell 中的过滤结果。请注意,默认情况下 nova list 使用 deleted=Falseproject_id=tenant_id 过滤器,由于我们从 instance_mapping 表中知道这两个值,因此它们将是允许的唯一过滤器。因此,只有执行 nova listnova list --minimal 才会显示下线 Cell 的简约结果。其他过滤器(如 nova list --deletednova list --host xx)将跳过下线 Cell 的结果。

  • 标记:如果用户执行 nova list --marker,如果标记位于下线 Cell 中,则将返回 500 错误。

  • 排序:我们忽略下线 Cell,就像我们忽略过滤器一样,因为无法从缺少关键信息的下线 Cell 获得有效结果。

  • 分页:我们忽略下线 Cell。例如,如果我们有三个 Cell A(已启动)、B(已下线)和 C(已启动),如果标记位于 A 的中间位置,我们将获得 A 的剩余一半结果、C 的所有结果并忽略 Cell B。

备选方案

  • 将删除信息添加到 instance_mappings 表中的替代方案是在各自的 RequestSpec 记录中,但是 PTG 决定继续在 instance_mappings 表中添加新列,因为它更合适。对于主要逻辑,如果列表操作需要在 Cell 下线时有效,则在 API DB 中拥有已删除信息没有替代解决方案。

  • 如果没有新的微版本,在列出下线 Cell 时,在响应中包含“shell”服务器,这些服务器将对缺失信息的键具有 UNKNOWN 值。但是,客户端无法处理带有“UNKNOWN”值的响应。此外,不可能将“UNKNOWN”分配给所有字段,因为并非所有字段都是字符串类型。

  • 使用新的微版本,在新的顶级 API 响应键 unavailable_servers 中包含下线 Cell 中的服务器 UUID 集合,并将两个列表(一个用于来自已启动 Cell 的服务器,另一个用于来自下线 Cell 的服务器)分开处理。有关更多详细信息,请参阅 unavailable_servers 的 POC

  • 使用 Searchlight 在有下线 Cell 时进行回填。有关更多详细信息,请参阅 使用 Searchlight 列出实例

  • 为每个 Cell 数据库添加备份数据库,这些数据库将在危机时刻充当原始数据库的只读副本,但是这需要大量的同步,并且可能会获取陈旧的结果。

数据模型影响

需要对 nova_api DB 模式进行更改,以便将类型为布尔值的 queued_for_delete 列添加到 nova_api.instance_mappings 表中。此列默认设置为 False。

此外,InstanceMapping 对象将具有一个名为 queued_for_delete 的新字段。将添加一个在线数据迁移工具来填充现有 instance_mappings 的此字段。该工具基本上将遍历所有 Cell 中的实例记录,如果实例的 vm_state 为 DELETED 或 SOFT_DELETED,则将 queued_for_delete 更新为 True,否则将其保留为默认值。

REST API 影响

当 Cell 下线时,我们当前会跳过该 Cell,本规范旨在为 GET /serversGET /os-servicesGET /servers/detailGET /servers/{server_id} REST API 提供部分信息。客户端将有一个新的微版本来识别响应中缺失的键和 NULL 值。

下面给出了 GET /servers/detail 的示例服务器响应,其中包含一个可用的服务器和一个不可用的服务器。

JSON 响应体示例

{
    "servers": [
        {
            "OS-EXT-STS:task_state": null,
            "addresses": {
                "public": [
                    {
                        "OS-EXT-IPS-MAC:mac_addr": "fa:xx:xx:xx:xx:1a",
                        "version": 4,
                        "addr": "1xx.xx.xx.xx3",
                        "OS-EXT-IPS:type": "fixed"
                    },
                    {
                        "OS-EXT-IPS-MAC:mac_addr": "fa:xx:xx:xx:xx:1a",
                        "version": 6,
                        "addr": "2sss:sss::s",
                        "OS-EXT-IPS:type": "fixed"
                    }
                ]
            },
            "links": [
                {
                    "href": "http://1xxx.xxx.xxx.xxx/compute/v2.1/servers/b546af1e-3893-44ea-a660-c6b998a64ba7",
                    "rel": "self"
                },
                {
                    "href": "http://1xx.xxx.xxx.xxx/compute/servers/b546af1e-3893-44ea-a660-c6b998a64ba7",
                    "rel": "bookmark"
                }
            ],
            "image": {
                "id": "9da3b809-2998-4ada-8cc6-f24bc0b6dd7f",
                "links": [
                    {
                        "href": "http://1xx.xxx.xxx.xxx/compute/images/9da3b809-2998-4ada-8cc6-f24bc0b6dd7f",
                        "rel": "bookmark"
                    }
                ]
            },
            "OS-EXT-SRV-ATTR:user_data": null,
            "OS-EXT-STS:vm_state": "active",
            "OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
            "OS-EXT-SRV-ATTR:root_device_name": "/dev/vda",
            "OS-SRV-USG:launched_at": "2018-06-29T15:07:39.000000",
            "flavor": {
                "ephemeral": 0,
                "ram": 64,
                "original_name": "m1.nano",
                "vcpus": 1,
                "extra_specs": {},
                "swap": 0,
                "disk": 0
            },
            "id": "b546af1e-3893-44ea-a660-c6b998a64ba7",
            "security_groups": [
                {
                    "name": "default"
                }
            ],
            "OS-SRV-USG:terminated_at": null,
            "os-extended-volumes:volumes_attached": [],
            "user_id": "187160b0afe041368258c0b195ab9822",
            "OS-EXT-SRV-ATTR:hostname": "surya-probes-001",
            "OS-DCF:diskConfig": "MANUAL",
            "accessIPv4": "",
            "accessIPv6": "",
            "OS-EXT-SRV-ATTR:reservation_id": "r-uxbso3q4",
            "progress": 0,
            "OS-EXT-STS:power_state": 1,
            "OS-EXT-AZ:availability_zone": "nova",
            "config_drive": "",
            "status": "ACTIVE",
            "OS-EXT-SRV-ATTR:ramdisk_id": "",
            "updated": "2018-06-29T15:07:39Z",
            "hostId": "e8dcf7ab9762810efdec4307e6219f85a53d5dfe642747c75a87db06",
            "OS-EXT-SRV-ATTR:host": "cn1",
            "description": null,
            "tags": [],
            "key_name": null,
            "OS-EXT-SRV-ATTR:kernel_id": "",
            "OS-EXT-SRV-ATTR:hypervisor_hostname": "cn1",
            "locked": false,
            "name": "surya-probes-001",
            "OS-EXT-SRV-ATTR:launch_index": 0,
            "created": "2018-06-29T15:07:29Z",
            "tenant_id": "940f47b984034c7f8f9624ab28f5643c",
            "host_status": "UP",
            "trusted_image_certificates": null,
            "metadata": {}
        },
        {
            "created": "2018-06-29T15:07:29Z",
            "status": "UNKNOWN",
            "tenant_id": "940f47b984034c7f8f9624ab28f5643c",
            "id": "bcc6c6dd-3d0a-4633-9586-60878fd68edb",
        }
    ]
}

安全影响

无。

通知影响

无。

其他最终用户影响

当无法连接 Cell 数据库时,nova listnova shownova service-list 将使用下线 Cell 中的记录,这些记录不包含所有信息。当这些命令与过滤器/排序/分页一起使用时,输出将完全跳过下线 Cell,并仅返回来自已启动 Cell 的信息。根据默认策略,如果该 tenant_id 在下线 Cell 中有任何正在运行的实例,nova boot 将无法工作。

性能影响

在正常情况下,对性能没有重大影响。但是,当 Cell 下线时,在 show/list/boot 时间,由于对 instance_mapping 和/或 request_spec 表的额外检查以及 scatter-gather 工具返回 did_not_respond_sentinel 时构建简约记录所需的时间,性能会略有下降。

其他部署者影响

无。

开发人员影响

无。

升级影响

由于 API DB 模式将发生变化,因此必须运行 nova-manage api_db sync 命令以更新 instance_mappings 表。将添加一个新的在线数据迁移工具来填充新列。

实现

负责人

主要负责人

<tssurya>

其他贡献者

<belmoreira>

工作项

  1. 在 nova_api.instance_mappings 表中添加一个新列 queued_for_delete

  2. 在 InstanceMapping 对象中添加一个新字段 queued_for_delete

  3. 添加一个新的在线迁移工具来填充现有 instance_mappings 的 queued_for_delete

  4. 优雅地处理在从 Cell 接收到超时时的 nova list 此处

  5. 优雅地处理在从 Cell 接收到超时时的 nova service-list

  6. 处理 nova boot 在配额计算期间,在 配额计算代码 中,当结果是 did_not_respond_sentinel 或 raised_exception_sentinel 时。在 instance_mapping 表中实现额外的检查,以查看请求项目在 down cell 中是否有任何存活实例,并相应地阻止请求。

依赖项

无。

测试

单元和功能测试,用于验证在接收到 did_not_respond_sentinel 时的正常工作情况。

文档影响

更新计算 API 参考的描述,关于这些命令,包括 UNKNOWN 记录的含义。

参考资料

历史

修订版

发布名称

描述

Rocky

引入