【问题标题】:paging the query result with multiple heads多头分页查询结果
【发布时间】:2018-11-18 13:06:24
【问题描述】:

我们有一个用于对象之间关系建模的微服务。在具有基数约束(如 1-1、1-N、N-N 等)的主要对象和次要对象之间定义关系。 微服务提供创建关系、查找关系、获取辅助项、获取主项等 API。

查询 API“获取辅助对象”获取主对象并返回所有相关的辅助对象。由于相关的次要对象可能很大,因此对结果进行了分页。

我们有另一个微服务,它很好地利用了这个关系微服务来处理关系。该消费服务接受类似的分页选项,如页面索引和编号,并将其传递给关系服务,并将从关系服务获得的页面结果返回给调用应用程序。到目前为止一切都很好。

我们最近发现,消费微服务与关系微服务有点啰嗦,因为它必须多次调用“获取辅助”API,因为有多个主要对象需要获取辅助对象。

因此,我们考虑让“Get Secondary”API 成为批量 API,使其接受多个主要对象作为输入。但后来我们陷入了分页的工作方式。 API 将为每个主要对象返回相关的次要对象,但像之前一样将次要对象限制为页面大小。
这对于第一次调用来说似乎很好,但我们不确定这对于后续调用会如何表现。如果辅助对象的数量少于一个或多个主要对象的页面大小,那么后续调用的输入应该是什么。我需要再次传递那些主要对象吗?

我们正在这里寻找有关如何设计此批量 API 的建议。欢迎任何意见。

【问题讨论】:

  • 您是否决定过解决方案?如果是这样,请随时添加您自己的答案来解释您所做的事情,以便其他人也可以从中学习。

标签: algorithm pagination microservices relation


【解决方案1】:

基本上,您应该有一些方法来确保关系服务在接收分页请求时知道原始查询是什么。

关系服务处理此问题的一种简单且可维护的方法是通过以某种方式对请求的主要对象进行排序(即按 Id 字母顺序排序)来预处理请求,然后简单地遍历主要对象,添加次要对象到响应,直到响应已满。

客户端做的最简单的事情是始终使用相同的批处理请求,只需在请求中添加索引号或页面令牌。

我建议使用提及上次看到的项目的页面标记(例如,lastSeen=primaryId,secondaryId(您应该以某种方式对其进行混淆以避免抽象泄漏))。然后,服务可以查看原始请求,并知道从哪里恢复遍历所有主要对象。

或者,您可以将足够的信息编码到页面令牌中,以便您可以从原始请求中重构您需要的任何内容。这允许您对后续请求的查询进行一些调整。 (例如,如果客户端请求主对象A-Z,并且您在第一个响应中返回辅助对象A1 - J5,那么您可以将请求修改为J-Z; already seen J5,对其进行编码,以免泄露您的实现细节,并将其作为页面令牌返回给客户端。)然后,客户端不再使用original request + page number 进行响应,而是使用页面令牌进行响应。

无论哪种方式,关系服务的客户都应该永远不必“弄清楚”下一页的请求应该是什么。分页应该只要求消费者增加一个数字或使用关系服务提供给它的页面令牌进行响应。

另一个考虑因素是您正在使用的数据库。例如,在 DynamoDB 中,为 select * from secondaries where primaryId='ABC' 之类的查询获取第 100 个项目的方法要求您读取直到第 100 个项目的所有项目。如果您有一个 NoSQL 数据库,或者如果您认为将来可能会迁移到 NoSQL 数据库,您可能会发现页面令牌可以更轻松地维护您在结果集中的位置(与索引号)。

当我自己学习分页时,我发现this article 非常有帮助,我建议您阅读它。它主要处理 UI 的分页问题,​​但基本原理是相同的。

TLDR:不要让消费者做任何工作。消费者应使用添加的索引号或页面令牌重复原始请求,或者消费者应发送仅包含页面令牌的请求。

【讨论】:

    猜你喜欢
    • 2020-12-31
    • 2021-09-11
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    相关资源
    最近更新 更多