查询批处理
使用 GraphOS Router 接收查询批次
此功能仅在 GraphOS 企业计划中可用.
您可以通过注册免费账户来测试它。 企业试用版.
了解关于查询批处理和如何配置GraphOS 路由器以接收查询批处理。
关于查询批处理
现代应用程序通常需要多个请求来渲染单个页面。这通常是组件化架构的结果,其中单独的微前端(MFE)分别发出请求以获取与其相关的数据。这不仅会导致性能开销——不同的组件可能请求相同的数据——还可能导致一致性问题。为了解决这个问题,基于MFE的用户界面将多个彼此紧密相连的客户操作组合成一个单独的HTTP请求。这在Apollo 客户端和Apollo 服务器中得到支持。
路由器的批处理支持通过两组功能提供:
- 客户端批处理
- 子图批处理
在客户端批处理中,路由器从客户端接收批处理请求,并单独处理批处理中的每个请求。因此,路由器以批量形式向子图呈现请求,因此子图必须单独处理批处理请求。
在子图批处理中,路由器分析输入客户端批处理请求并向子图发出批处理请求。子图批处理是客户端批处理的扩展,需要参与的子图支持批处理请求。以下是说明如何在实践中工作的示例。
GraphOS 路由器支持客户端和子图查询批处理。
如果您使用的是Apollo 客户端,则可以利用内置的批处理支持来减少发送到路由器的单独操作的数量。
配置后,Apollo 客户端将自动将多个操作组合成一个单独的HTTP请求。批次内的操作数量由客户端配置,包括批次中的最大数量和等待操作累积发送批次的最大持续时间。
GraphOS 路由器必须配置为接收查询批次,否则它将拒绝它们。在处理批处理时,路由器将单独反序列化和处理批处理中的每个操作。仅在批次中的所有操作都完成后,才对客户端做出响应。每个操作与其他批处理中的操作并发执行。
配置客户端查询批处理
GraphOS 路由器和客户端都需要配置以支持查询批处理。
配置路由器
客户端查询批处理
默认情况下,GraphOS 路由器不启用接收客户端查询批次。
要启用查询批量处理,请设置以下字段在您的router.yaml
配置文件中:
batching:enabled: truemode: batch_http_link
属性 | 描述 | 有效值 | 默认值 |
---|---|---|---|
enabled | 启用接收客户端查询批次的标志 | 布尔类型 | false |
mode | 支持客户端批量模式 | batch_http_link :客户端使用 Apollo Link 及其 BatchHttpLink 连接。 | 无默认值 |
子图查询批量处理
如果启用客户端查询批量处理,并且路由器的子图支持查询批量处理,则可以通过设置以下字段在您的router.yaml
配置文件中启用子图查询批量处理:
batching:enabled: truemode: batch_http_linksubgraph:# Enable batching on all subgraphsall:enabled: true
batching:enabled: truemode: batch_http_linksubgraph:# Disable batching on all subgraphsall:enabled: false# Configure(over-ride) batching support per subgraphsubgraphs:subgraph_1:enabled: truesubgraph_2:enabled: true
ⓘ 注意
示例:简单的子图批量处理
此示例显示路由器如何在查询批次中不包含必需的获取约束的最多效场景中对子图请求进行批量处理。
假设联邦的图包含三个子图accounts
,products
和reviews
。
输入客户端 查询到联盟 图:
[{"query":"query MeQuery1 {\n me {\n id\n }\n}"}{"query":"query MeQuery2 {\n me {\n name\n }\n}"},{"query":"query MeQuery3 {\n me {\n id\n }\n}"}{"query":"query MeQuery4 {\n me {\n name\n }\n}"},{"query":"query MeQuery5 {\n me {\n id\n }\n}"}{"query":"query MeQuery6 {\n me {\n name\n }\n}"},{"query":"query MeQuery7 {\n me {\n id\n }\n}"}{"query":"query MeQuery8 {\n me {\n name\n }\n}"},{"query":"query MeQuery9 {\n me {\n id\n }\n}"}{"query":"query MeQuery10 {\n me {\n name\n }\n}"},{"query":"query MeQuery11 {\n me {\n id\n }\n}"}{"query":"query MeQuery12 {\n me {\n name\n }\n}"},{"query":"query MeQuery13 {\n me {\n id\n }\n}"}{"query":"query MeQuery14 {\n me {\n name\n }\n}"},{"query":"query MeQuery15 {\n me {\n id\n }\n}"}]
从输入 查询中,路由器 生成了一个子图 查询集:
"query MeQuery1__accounts__0{me{id}}","query MeQuery2__accounts__0{me{name}}","query MeQuery3__accounts__0{me{id}}","query MeQuery4__accounts__0{me{name}}","query MeQuery5__accounts__0{me{id}}","query MeQuery6__accounts__0{me{name}}","query MeQuery7__accounts__0{me{id}}","query MeQuery8__accounts__0{me{name}}","query MeQuery9__accounts__0{me{id}}","query MeQuery10__accounts__0{me{name}}","query MeQuery11__accounts__0{me{id}}","query MeQuery12__accounts__0{me{name}}","query MeQuery13__accounts__0{me{id}}","query MeQuery14__accounts__0{me{name}}","query MeQuery15__accounts__0{me{id}}",
所有的查询可以合并成一个批次。因此,而不是15个(非批量)子图 获取操作,路由器 只需要进行一次获取。
子图 | 获取次数(无) | 获取次数(有) |
---|---|---|
账户 | 15 | 1 |
示例:复杂的子图批量处理
此示例展示了路由器如何批量处理某图中的子图 请求,其中客户端批次包含对一个 查询的 实体 。
假设联盟 图包含三个 子图: accounts
、products
和reviews
。
输入客户端 查询到联盟 图:
[{"query":"query MeQuery1 {\n me {\n id\n }\n}"},{"query":"query MeQuery2 {\n me {\n reviews {\n body\n }\n }\n}"},{"query":"query MeQuery3 {\n topProducts {\n upc\n reviews {\n author {\n name\n }\n }\n }\n me {\n name\n }\n}"},{"query":"query MeQuery4 {\n me {\n name\n }\n}"},{"query":"query MeQuery5 {\n me {\n id\n }\n}"}]
从输入 查询中,路由器 生成了一个子图 查询集:
"query MeQuery1__accounts__0{me{id}}","query MeQuery2__accounts__0{me{__typename id}}","query MeQuery3__products__0{topProducts{__typename upc}}","query MeQuery3__accounts__3{me{name}}","query MeQuery4__accounts__0{me{name}}","query MeQuery5__accounts__0{me{id}}","query MeQuery2__reviews__1($representations:[_Any!]!){_entities(representations:$representations){...on User{reviews{body}}}}","query MeQuery3__reviews__1($representations:[_Any!]!){_entities(representations:$representations){...on Product{reviews{author{__typename id}}}}}","query MeQuery3__accounts__2($representations:[_Any!]!){_entities(representations:$representations){...on User{name}}}",
前六个查询可以合并成两个批次——一个用于 accounts
,一个用于products
。它们必须先获取,才能单独执行最后的三个查询。
总的来看,没有子图批处理后,路由器在三个子图上总共进行9次获取,但有了子图批处理后,总数减少到5次。
子图 | 获取次数(无) | 获取次数(有) |
---|---|---|
账户 | 6 | 2 |
products | 1 | 1 |
reviews | 2 | 2 |
配置客户端
要在 Apollo 客户端中启用批量处理,请配置 BatchHttpLink
。有关实现 BatchHttpLink
的详细信息,请参阅 批量操作。
配置兼容性
如果路由器从一个客户端接收查询批量,且批量处理 未启用,则路由器向客户端发送一个 BATCHING_NOT_ENABLED
错误。
查询批量的指标
GraphOS Router 中查询批量的指标:
名称 | 属性 | 描述 |
---|---|---|
| 模式 [subgraph] | 接收(来自客户端)或派发(到子图)批量的计数器。 |
| 模式 [subgraph] | 接收批量大小的直方图。 |
如果存在 subgraph
属性,则是可选的。如果不存在该属性,则指标标识来自客户端的批量。如果存在该属性,则指标标识发送到特定 subgraph 的批量。
查询批量格式
请求格式
查询批量是一系列的 operations 数组。
[query MyFirstQuery {me {id}},query MySecondQuery {me {name}}]
响应格式
响应以 JSON 数组形式提供,其中响应顺序与查询批量中操作的顺序相匹配。
[{"data":{"me":{"id":"1"}}},{"data":{"me":{"name":"Ada Lovelace"}}}]
查询批量的错误处理
批量错误
如果无法处理查询批量,则整个批量会失败。
例如,此批量请求是无效的,因为它有两个逗号分隔构成查询。
[query MyFirstQuery {me {id}},,query MySecondQuery {me {name}}]
因此,路由器返回一个无效批量错误:
{"errors":[{"message":"Invalid GraphQL request","extensions":{"details":"failed to deserialize the request body into JSON: expected value at line 1 column 54","code":"INVALID_GRAPHQL_REQUEST"}}]}
单个查询错误
如果在批量中单个查询无法处理,这将导致单个错误。
例如,查询 MyFirstQuery
访问一个不存在的 字段,而其余的批处理查询是有效的。
[query MyFirstQuery {me {thisfielddoesnotexist}},query MySecondQuery {me {name}}]
因此,对单个无效查询返回一个错误,而其他(有效)查询返回一个响应。
[{"errors":[{"message":"cannot query field 'thisfielddoesnotexist' on type 'User'","extensions":{"type":"User","field":"thisfielddoesnotexist","code":"INVALID_FIELD"}}]},{"data":{"me":{"name":"Ada Lovelace"}}}]
已知限制
不支持的查询模式
启用批量处理时,任何导致响应流的结果的批量操作都不受支持,包括: