性能
¥Performance
Optimize the execution and delivery of GraphQL responses
乍一看,由于 API 是通过单个端点提供的,并且你可能事先不知道客户端将在操作中包含哪些字段,因此 GraphQL 请求似乎很难缓存。
¥At first glance, GraphQL requests may seem challenging to cache given that the API is served through a single endpoint and you may not know in advance what fields a client will include in an operation.
然而,在实践中,GraphQL 与任何支持参数化请求的 API 一样可缓存,例如允许客户端为特定端点指定不同查询参数的 REST API。有很多方法可以在客户端和服务器端以及传输层优化 GraphQL 请求,不同的 GraphQL 服务器和客户端库通常会直接内置常见的缓存功能。
¥In practice, however, GraphQL is as cacheable as any API that enables parameterized requests, such as a REST API that allows clients to specify different query parameters for a particular endpoint. There are many ways to optimize GraphQL requests on the client and server sides, as well as in the transport layer, and different GraphQL server and client libraries will often have common caching features built directly into them.
在此页面上,我们将探索可在 GraphQL 客户端和服务器中利用的几种不同策略,以优化从 API 获取数据的方式。
¥On this page, we’ll explore several different tactics that can be leveraged in GraphQL clients and servers to optimize how data is fetched from the API.
客户端缓存
¥Client-side caching
GraphQL 客户端可以实现一系列客户端缓存策略,不仅有助于提高性能,还可以确保为用户呈现一致且响应迅速的界面。阅读有关客户端缓存的更多信息。
¥There is a range of client-side caching strategies that GraphQL clients may implement to help not only with performance but also to ensure that you render a consistent and responsive interface to your users. Read more about client-side caching.
GET
查询请求
¥GET
requests for queries
遵守 GraphQL over HTTP 规范 的 GraphQL 实现默认支持 POST
HTTP 方法,但也可能支持查询操作的 GET
请求。
¥GraphQL implementations that adhere to the GraphQL over HTTP specification will support the POST
HTTP method by default, but may also support GET
requests for query operations.
使用 GET
可以提高查询性能,因为使用此 HTTP 方法发出的请求通常默认被视为可缓存,并且当服务器响应中提供与缓存相关的标头时,可以帮助促进 HTTP 缓存或内容传送网络 (CDN) 的使用。
¥Using GET
can improve query performance because requests made with this HTTP method are typically considered cacheable by default and can help facilitate HTTP caching or the use of a content delivery network (CDN) when caching-related headers are provided in the server response.
但是,由于浏览器和 CDN 对 URL 施加了大小限制,因此可能无法在 URL 的查询字符串中发送用于复杂操作的大型文档。使用持久查询(以受信任文档或自动持久查询的形式)将允许客户端发送查询的哈希值,并且服务器可以在验证和执行操作之前通过在服务器端存储中查找哈希来查找文档的完整版本。
¥However, because browsers and CDNs impose size limits on URLs, it may not be possible to send a large document for complex operations in the query string of the URL. Using persisted queries, either in the form of trusted documents or automatic persisted queries, will allow the client to send a hash of the query instead, and the server can look up the full version of the document by looking up the hash in a server-side store before validating and executing the operation.
发送散列查询而不是纯文本版本还有一个额外的好处,那就是减少客户端在网络请求中发送的数据量。
¥Sending hashed queries instead of their plaintext versions has the additional benefit of reducing the amount of data sent by the client in the network request.
N+1 问题
¥The N+1 Problem
GraphQL 的设计方式允许你在服务器上编写干净的代码,其中每种类型的每个字段都有一个集中的单一用途函数来解析该值。但是,如果不进行额外考虑,简单的 GraphQL 服务可能会非常 “chatty” 或重复从数据库加载数据。
¥GraphQL is designed in a way that allows you to write clean code on the server, where every field on every type has a focused single-purpose function for resolving that value. However, without additional consideration, a naive GraphQL service could be very “chatty” or repeatedly load data from your databases.
考虑以下查询 - 为了获取英雄及其朋友列表,我们可以想象,当字段解析器执行时,将向底层数据源发出一个请求以获取角色对象,另一个请求获取他们的朋友,然后是三个后续请求加载每个人类朋友的星际飞船列表:
¥Consider the following query—to fetch a hero along with a list of their friends, we can imagine that as the field resolvers execute there will be one request to the underlying data source to get the character object, another to fetch their friends, and then three subsequent requests to load the lists of starships for each human friend:
这被称为 N+1 问题,其中对底层数据源的初始请求(针对英雄的朋友)会导致 N 个后续请求来解析所有请求字段的数据(针对朋友的星舰数据)。
¥This is known as the N+1 problem, where an initial request to an underlying data source (for a hero’s friends) leads to N subsequent requests to resolve the data for all of the requested fields (for the friends’ starship data).
这通常通过批处理技术解决,其中在短时间内收集来自后端的多个数据请求,然后使用 Facebook 的 DataLoader 等工具在单个请求中发送到底层数据库或微服务。此外,某些 GraphQL 实现可能具有内置功能,允许你将操作选择集转换为对底层数据源的优化查询。
¥This is commonly solved by a batching technique, where multiple requests for data from a backend are collected over a short period and then dispatched in a single request to an underlying database or microservice by using a tool like Facebook’s DataLoader. Additionally, certain GraphQL implementations may have built-in capabilities that allow you to translate operation selection sets into optimized queries to underlying data sources.
需求控制
¥Demand control
根据 GraphQL 模式的设计方式,客户端可能会请求高度复杂的操作,这些操作在执行期间会对底层数据源造成过大的负载。这些类型的操作可能是由已知客户端无意发送的,但也可能是由恶意行为者发送的。
¥Depending on how a GraphQL schema has been designed, it may be possible for clients to request highly complex operations that place excessive load on the underlying data sources during execution. These kinds of operations may be sent inadvertently by an known client, but they may also be sent by malicious actors.
某些需求控制机制可以帮助保护 GraphQL API 免受这些操作的影响,例如分页列表字段、限制操作深度和广度以及查询复杂性分析。你可以在安全页面上阅读有关需求控制的更多信息。
¥Certain demand control mechanisms can help guard a GraphQL API against these operations, such as paginating list fields, limiting operation depth and breadth, and query complexity analysis. You can read more about demand control on the Security page.
JSON(带 GZIP)
¥JSON (with GZIP)
GraphQL 服务通常使用 JSON 响应,即使 GraphQL 规范为 不需要它。对于承诺提供更好网络性能的 API 层来说,JSON 似乎是一个奇怪的选择,但是,由于它主要是文本,因此可以使用 GZIP、deflate 和 brotli 等算法进行非常好的压缩。
¥GraphQL services typically respond using JSON even though the GraphQL spec does not require it. JSON may seem like an odd choice for an API layer promising better network performance, however, because it is mostly text it compresses exceptionally well with algorithms such as GZIP, deflate and brotli.
我们鼓励任何生产 GraphQL 服务启用 GZIP 并鼓励其客户端发送标头:
¥It’s encouraged that any production GraphQL services enable GZIP and encourage their clients to send the header:
Accept-Encoding: gzip
JSON 对于客户端和 API 开发者来说也非常熟悉,并且易于阅读和调试。事实上,GraphQL 语法部分受到 JSON 语法的启发。
¥JSON is also very familiar to client and API developers, and is easy to read and debug. In fact, the GraphQL syntax is partly inspired by JSON syntax.
性能监控
¥Performance monitoring
通过长期监控 GraphQL API,你可以了解某些操作如何影响 API 性能,并帮助你确定需要进行哪些调整才能保持其健康。例如,你可能会发现由于对后备数据源的请求未得到充分优化,某些字段需要很长时间才能解析,或者你可能会发现其他字段在执行过程中经常出现错误。
¥Monitoring a GraphQL API over time can provide insight into how certain operations impact API performance and help you determine what adjustments to make to maintain its health. For example, you may find that certain fields take a long time to resolve due to under-optimized requests to a backing data source, or you may find that other fields routinely raise errors during execution.
可观察性工具可以深入了解某些 GraphQL 操作执行过程中的瓶颈,方法是允许你检测 API 服务以在请求期间收集指标、跟踪和日志。例如,OpenTelemetry 提供了一套与供应商无关的工具,可用于多种不同的语言来支持 GraphQL API 的检测。
¥Observability tooling can provide insight into where bottlenecks exist in the execution of certain GraphQL operations by allowing you to instrument the API service to collect metrics, traces, and logs during requests. For example, OpenTelemetry provides a suite of vendor-agnostic tools that can be used in many different languages to support instrumentation of GraphQL APIs.
回顾
¥Recap
回顾这些关于提高 GraphQL API 性能的建议:
¥To recap these recommendations for improving GraphQL API performance:
-
使用
GET
进行 GraphQL 查询操作可以支持 HTTP 缓存和 CDN 使用,特别是与散列查询文档结合使用时¥Using
GET
for GraphQL query operations can support HTTP caching and CDN usage, particularly when used in conjunction with hashed query documents -
由于操作的选择集可以表达不同类型对象之间的关系,因此可以通过将请求分批并缓存到底层数据源来缓解字段执行期间的 N+1 问题
¥Because an operation’s selection set can express relationships between different kinds of objects, the N+1 problem can be mitigated during field execution by batching and caching requests to underlying data sources
-
字段分页、限制操作深度和广度以及限制 API 请求速率可以帮助防止单个 GraphQL 操作对服务器资源造成过大负载
¥Field pagination, limiting operation depth and breadth, and rate-limiting API requests can help prevent individual GraphQL operations from placing excessive load on server resources
-
当服务器和客户端支持时,GZIP 可用于压缩 GraphQL JSON 格式响应的大小
¥GZIP can be used to compress the size of GraphQL JSON-formatted responses when servers and clients support it
-
通过使用 OpenTelemetry 等性能监控工具收集与请求执行相关的指标、日志和跟踪,可以长期维护 GraphQL API 的整体运行状况
¥The overall health of a GraphQL API can be maintained over time by using performance monitoring tools like OpenTelemetry to collect metrics, logs, and traces related to request execution