Cinder 分页排序增强

https://blueprints.launchpad.net/cinder/+spec/cinder-pagination

目前,Cinder 的排序支持允许调用者指定单个排序键和排序方向。此蓝图增强了 /volumes 和 /volumes/detail API 的排序支持,以便可以在请求中提供多个排序键和排序方向。

问题描述

目前不支持基于多个排序键检索卷数据;当前仅支持单个排序键和方向,并且默认按“created_at”键降序排序。为了能够以任何排序顺序和方向检索数据,REST API 需要接受多个排序键和方向。

用例:一个 UI 显示一个表格,该表格仅显示从服务器检索到的数据页面。此表格中的项目需要首先按状态排序,然后按显示名称排序。为了以这种顺序检索数据,API 必须接受多个排序键/方向。

用例

提议的变更

/volumes 和 /volumes/detail API 将符合 API 工作组指南(参见参考文献部分)的排序要求,并在请求中支持以下参数

  • sort:逗号分隔的排序键列表,每个键可以选择性地附加 <:dir>,其中 ‘dir’ 是相应排序键的方向(支持的值为 ‘asc’ 表示升序,‘desc’ 表示降序)

例如:/volumes?sort=status:asc,display_name:asc,created_at:desc

注意:“created_at”和“id”排序键始终附加在键列表的末尾,如果它们尚未在请求中指定。

数据库层已经支持多个排序键和方向。此蓝图将更新 API 层以从 API 请求中检索排序信息,并将该信息传递到数据库层。

所有排序都在 cinder.common.sqlalchemyutils.paginate_query 函数中处理。此函数将 ORM 模型类作为参数,并且唯一的有效排序键是给定模型类上的属性。因此,有效的排序键仅限于 models.Volume 类上的模型属性。

备选方案

可以使用重复的 ‘sort_key’ 和 ‘sort_dir’ 查询参数传递多个排序键和方向。例如

/volumes?sort_key=status&sort_dir=asc&sort_key=display_name&sort_dir=asc& sort_key=created_at&sort_dir=desc

但是,这不符合 API 排序指南。

此外,可以根据新扩展的存在有条件地启用此额外的排序;但是,由于已经支持按单个键排序,因此可能不需要新的扩展来增强对多个键/方向的支持。但是,如果需要,可以创建扩展。

数据模型影响

REST API 影响

以下现有的 v2 GET API 将支持新的排序参数

  • /v2/{tenant_id}/volumes

  • /v2/{tenant_id}/volumes/detail

请注意,此蓝图描述的设计可以应用于其他 GET REST API,但此蓝图的范围仅限于上述 API。一旦此设计完成,就可以将相同的方法应用于其他 API。

现有的 API 文档需要更新,以包含以下新的请求参数

参数

风格

类型

描述

sort

query

string

逗号分隔的排序键列表和可选的排序方向,形式为 key<:dir>,其中 ‘dir’ 要么是 ‘asc’ 表示升序,要么是 ‘desc’ 表示降序。默认值为 ‘created_at’ 和 ‘id’ 键降序。

目前,volumes 查询支持 ‘sort_key’ 和 ‘sort_dir’ 参数;这些将被弃用。如果同时指定了新的 ‘sort’ 参数和弃用的 ‘sort_key’ 或 ‘sort_dir’ 参数,API 将引发“badRequest”错误响应(代码 400)。

API 响应格式和返回代码不会被修改,只会修改返回的卷的顺序。

如果指定了无效的排序键,将返回“badRequest”错误响应(代码 400),并附带类似于“Invalid input received: Invalid sort key”的消息。

安全影响

通知影响

其他最终用户影响

cinderclient 应更新为接受排序键和排序方向,使用跨项目规范中提出的 ‘sort’ 参数:https://review.openstack.org/#/c/145544/

性能影响

所有排序都将在数据库中完成。排序键的选择仅限于 models.Volume ORM 类上的属性 – 不是从详细查询返回的每个属性键都是有效的排序键。

通过在简单的 devstack VM(2GB 内存)上运行来收集性能数据。将 5000 个卷插入到 DB 中。数据显示,主数据表上的排序时间在运行详细查询时被大大缩短(参见下表) – 大部分时间都花在查询其他表以获取每个项目的信息上;因此,排序键对详细查询的影响很小。

例如,下表比较了非详细查询的 GET 请求处理时间与使用默认排序键的各种限制的详细查询的处理时间。此表的目的在于显示详细查询的处理时间主要由获取每个项目的其他详细信息决定。

限制

非详细 (秒)

详细 (秒)

非详细 / 详细 %

50

0.0560

0.8621

6.5%

100

0.0813

1.6839

4.8%

150

0.0848

2.4705

3.4%

200

0.0874

3.2502

2.7%

250

0.0985

4.1237

2.4%

300

0.1229

4.8731

2.5%

350

0.1262

5.6366

2.2%

400

0.1282

6.5573

2.0%

450

0.1458

7.2921

2.0%

500

0.1770

8.1126

2.2%

1000

0.2589

16.0844

1.6%

还收集了非详细查询数据。下表比较了使用默认排序键与使用 display_name 作为排序键的处理时间。添加的项目具有 40 个字符的 display_name,该 display_name 以非字母顺序生成。

限制

默认键 (秒)

display_name 键 (秒)

减速 %

50

0.0560

0.0600

7.1%

100

0.0813

0.0832

2.3%

150

0.0848

0.0879

3.7%

200

0.0874

0.0906

3.7%

250

0.0985

0.1031

4.7%

300

0.1229

0.1198

-2.5%

350

0.1262

0.1319

4.5%

400

0.1282

0.1368

6.7%

450

0.1458

0.1458

0.0%

500

0.1770

0.1619

-8.5%

1000

0.2589

0.2659

2.7%

结论:主数据表上的排序处理对整体处理时间的影响很小。对于详细查询,排序时间被其他处理所掩盖 – 即使排序时间增加 3 倍,也仅代表详细查询中 4.8% 的总处理时间(限制为 1000)(并且仅将处理时间增加 0.11 秒,限制为 50)。

其他部署者影响

排序键的选择对数据检索性能的影响很小(参见上面的性能数据)。因此,应允许用户以他们需要的方式检索数据来创建他们的视图(参见问题描述中的用例)。

开发人员影响

实现

负责人

主要负责人

kaufer (kaufer@us.ibm.com)

其他贡献者

工作项

理想情况下,处理排序参数的逻辑应在所有组件之间通用,并在 oslo 中完成;一个类似的蓝图也在 nova 中提出:https://blueprints.launchpad.net/nova/+spec/nova-pagination

因此,我看到以下工作项目

  • 复制 nova 中提出的通用代码来处理排序参数,参见 https://review.openstack.org/#/c/95260/。一旦两个项目都使用相同的代码,它应该被移动到 oslo。

  • 更新 API 以检索排序信息并传递到 DB 层(需要更改 volume/api.py、db/api.py 和 db/sqlalchemy/api.py)

  • 更新 cinderclient 以接受和处理多个排序键和排序方向

依赖项

测试

需要创建单元和 Tempest 测试来确保数据以指定的排序顺序检索。测试还应验证默认排序键(“created_at”和“id”)始终附加到用户提供的键(如果用户尚未指定它们)。

应针对多种后端数据库类型进行测试。

文档影响

/volumes 和 /volumes/detail API 文档需要更新为

  • 反映新的排序参数并解释这些参数将影响数据返回的顺序。

  • 解释默认排序键将始终添加到排序键列表的末尾

文档还可以指出查询性能会受到排序键选择的影响,并指出哪些键已编入索引。

参考资料

API 工作组排序指南:https://github.com/openstack/api-wg/blob/master/guidelines/ pagination_filter_sort.rst