简单的租户使用量分页

https://blueprints.launchpad.net/nova/+spec/paginate-simple-tenant-usage

该蓝图旨在为 GET /os-simple-tenant-usage 端点添加可选的 limitmarker 参数。

GET /os-simple-tenant-usage?limit={limit}&marker={instance_uuid}
GET /os-simple-tenant-usage/{tenant_id}?limit={limit}&marker={instance_uuid}

问题描述

简单的租户使用量 API 可能会返回大量数据,并且没有提供分页结果的方式。由于该 API 不使用分页代码,它甚至不遵守“最大结果数”的合理限制。因为它能够查询大量数据,还会导致 API worker 进程的内存占用量膨胀到数据库结果集的大小,而数据库结果集通常很大。由于 Horizon 默认查询此 API,大多数用户都会受到影响,除非他们的运维团队非常勤奋地清理已删除的实例(API 默认会返回已删除的实例)。

用例

Horizon 使用这些端点来显示服务器使用情况。

提议的变更

添加一个 API 微版本,允许使用 Nova 现有的分页方法(可选的 limitmarker 查询参数)对简单的租户使用量结果进行分页。

分页将适用于“所有租户”(index)和“特定租户”(show)两种情况。

List Tenant Usage For All Tenants
/os-simple-tenant-usage?limit={limit}&marker={instance_uuid}

Show Usage Details For Tenant
/os-simple-tenant-usage/{tenant_id}?limit={limit}&marker={instance_uuid}

目前,简单的租户使用量端点包含聚合数据(例如 total_hours),它是特定时间窗口内每个实例的 hours 的总和,按租户分组。

注意

为了清晰起见,我从示例中删除了所有其他使用量响应字段。

GET /os-simple-tenant-usage?detailed=1

{
    "tenant_usages": [
        {
            "server_usages": [
                {
                    "instance_id": "instance-uuid-1",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                },
                {
                    "instance_id": "instance-uuid-2",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                },
                {
                    "instance_id": "instance-uuid-3",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                }
            ],
            "tenant_id": "tenant-uuid-1",
            "total_hours": 3
        },
        {
            "server_usages": [
                {
                    "instance_id": "instance-uuid-4",
                    "tenant_id": "tenant-uuid-2",
                    "hours": 1
                }
            ],
            "tenant_id": "tenant-uuid-2",
            "total_hours": 1
        }
    ]
}

一旦引入分页,API 消费者如果仍然需要特定时间窗口内所有实例的总数,按租户分组,则需要将聚合结果拼接在一起。

例如,如果将 limit 查询参数设置为 2,则会以以下方式返回相同的数据。请注意,第一页结果中的总数仅反映了 tenant-uuid-1 的 2 个实例,并且第二页结果中的 tenant-uuid-1 总数仅反映了 tenant-uuid-1 的剩余实例。如果 API 消费者想要总数反映 tenant-uuid-1 的所有 3 个实例,则需要手动将这些总数加起来。

/os-simple-tenant-usage?detailed=1&limit=2

{
    "tenant_usages": [
        {
            "server_usages": [
                {
                    "instance_id": "instance-uuid-1",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                },
                {
                    "instance_id": "instance-uuid-2",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                }
            ],
            "tenant_id": "tenant-uuid-1",
            "total_hours": 2
        },
    ],
    "tenant_usages_links": [
        {
            "href": "/os-simple-tenant-usage?detailed=1&limit=2&marker=instance-uuid-2",
            "rel": "next"
        }
    ]
}
/os-simple-tenant-usage?detailed=1&limit=2&marker=instance-uuid-2

{
    "tenant_usages": [
        {
            "server_usages": [
                {
                    "instance_id": "instance-uuid-3",
                    "tenant_id": "tenant-uuid-1",
                    "hours": 1
                }
            ],
            "tenant_id": "tenant-uuid-1",
            "total_hours": 1
        },
        {
            "server_usages": [
                {
                    "instance_id": "instance-uuid-4",
                    "tenant_id": "tenant-uuid-2",
                    "hours": 1
                }
            ],
            "tenant_id": "tenant-uuid-2",
            "total_hours": 1
        },
    ]
}

分页是在内部的 server_usages 列表中完成的。 marker 是上一页 server_usages 列表中的最后一个实例 UUID。

简单的租户使用量端点还将包含常规的“next”链接:tenant_usages_linksindex 的情况下,以及 tenant_usage_linksshow 的情况下。

/os-simple-tenant-usage?detailed=1&limit={limit}

{
    "tenant_usages": [
        {
            "server_usages": [
               ...
            ],
            "tenant_id": "{tenant_id}",
        }
    ],
    "tenant_usages_links": [
        {
            "href": "/os-simple-tenant-usage?detailed=1&limit={limit}&marker={marker}",
            "rel": "next"
        }
    ]
}
/os-simple-tenant-usage/{tenant_id}?detailed=1&limit={limit}

{
    "tenant_usage": {
        "server_usages": [
           ...
        ]
    },
    "tenant_usage_links": [
        {
            "href": "os-simple-tenant-usage/{tenant_id}?limit={limit}&marker={marker}",
            "rel": "next"
        }
    ]
}

注意

为了清晰起见,我省略了“next”链接中的其他查询参数(例如 start & end),但它们需要保留。实际的 next 链接可能如下所示。

"tenant_usages_links": [
    {
        "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/os-simple-tenant-usage?detailed=1&end=2016-10-12+18%3A22%3A04.868106&limit=1&marker=1f1deceb-17b5-4c04-84c7-e0d4499c8fe0&start=2016-10-12+18%3A22%3A04.868106",
        "rel": "next"
    }
]

备选方案

数据模型影响

需要为返回 server_usages 列表中的实例的查询添加排序。排序顺序需要在 cell 数据库之间保持确定性,并且我们可能需要修改/添加新的数据库索引作为结果。

REST API 影响

添加一个 API 微版本,允许使用可选的 limitmarker 查询参数对简单的租户使用量结果进行分页。如果未提供 limit,它将默认为 CONF.osapi_max_limit,当前为 1000。

GET /os-simple-tenant-usage?limit={limit}&marker={instance_uuid}
GET /os-simple-tenant-usage/{tenant_id}?limit={limit}&marker={instance_uuid}

旧版本的 os-simple-tenant-usage 端点将不会接受这些新的分页查询参数,但它们将开始默默地限制为 CONF.osapi_max_limit,以鼓励采用这个新的微版本,并规避在拥有数千个实例的系统上可能出现的类似 DoS 的使用量请求。

安全影响

通知影响

其他最终用户影响

同时更改 python-novaclient 以接受简单的租户使用量的 limitmarker 选项。

性能影响

Horizon 消耗这些 API 端点,在实例很多时,这些端点目前运行缓慢且内存占用量大。

其他部署者影响

开发人员影响

实现

负责人

主要负责人

diana_clarke

其他贡献者

工作项

  • 为简单的租户使用量分页创建一个新的 API 微版本。

  • 更新 python-novaclient 以能够利用这些更改。

  • 将这些更改告知 Horizon 团队。

依赖项

测试

需要功能和单元测试。

文档影响

更新计算 api-ref 的“使用量报告”部分,以提及新的微版本和可选的 limitmarker 查询参数。

参考资料

描述问题的 Bug

[1] https://bugs.launchpad.net/nova/+bug/1421471

概念验证 (nova & python-novaclient)

[2] https://review.openstack.org/#/c/386093/

[3] https://review.openstack.org/#/c/394653/

历史

修订版

发布名称

描述

Ocata

引入