除了简化前端,REST也让监控等方面变得更加简单。据此,后端团队可以考量每一个端点的状态,并能够及时地发现当前出现的问题。当然,在使用的过程中,我们需要考虑清楚的最关键问题是:如何使用GraphQL来准确地监控到目标系统的重要位置。下面,让我们一起来讨论那些有关GraphQL APIs监控的优秀实践。
GraphQL架构
为了弄清楚上述问题件,让我们首先来了解GraphQL的架构。通常,一个简单的GraphQL系统会包括如下三个部分:
- 一种可定义所有数据类型的schema(结构模式)。
- 一个使用该schema将查询到的每个部分都路由到某个解析器(resolver)的GraphQL引擎。
- 一到多个能够被GraphQL引擎所调用的解析器。
通过解析schema,GraphQL后端会让服务器了解到哪种解析器能够处理哪种类型的查询。也就是说,当一个查询被发送到GraphQL端点时,GraphQL引擎会解析该查询中的每一种请求类型,进而调用解析器来满足其请求。可以想象,此类方法仅限于在与简单查询一起使用时,才能提供卓越的性能。
有时候,查询的某些部分会被连接到同一个数据源(包括数据库或第三方API等)。例如,如果我们加载某个用户的账号及其地址,它们可能在GraphQL的schema中具有两种类型,而在数据源中却只有一条记录。那么我们同时发出请求的时候,当然不希望服务器对同一个数据源发出两次查询请求。
针对上述问题,业界会采用一种被称为数据加载器(data-loader)的模式。该数据加载器是位于解析器和数据源之间的另一个GraphQL API层。通过简单的设置,解析器将能够直接访问到数据源。而在更为复杂的迭代中,解析器则会告诉数据加载器它们到底需要什么,据此加载器也会针对该目的去访问数据源。
那么,由此带来的好处是:数据加载器可以持续等待,直到所有的解析器都已被调用,并且完成了对于数据源的访问为止。针对上面提到的例子,如果有人想加载用户的账号和地址的话,那么只需对数据源发出一个请求便可。
可见,解析器只需了解其对应的需求,而数据加载器则需要知道所有解析器的目的,并据此来优化具体的访问。
监控GraphQL
有了上面的理论基础,我们就可以根据自己的架构,在如下多个位置监控GraphQL API了:
- HTTP端点:针对那些影响到我们API的所有流量。
- GraphQL查询:针对每个特定的查询。
- GraphQL解析器或数据加载器:针对数据源的每个访问。
- 全栈追踪:针对每个查询所影响到的解析器和数据加载器。
1. HTTP端点
在GraphQL架构中,通常只有一个HTTP端点,因此在该REST API级别上的监控,往往只能让我们了解到有关API总体状态的信息。
当然,这只是我们监控的一个起点。如果能够提供低延迟、低错误率的全量信息,而且客户端并无任何投诉产生的话,那么这些指标完全可以为我们节约后续花在深度监控上的大量时间和精力。但是,如果某个地方出现了问题,我们就需要更深入地进行探究了。
2. GraphQL查询
下面,我们需要监控每一个查询,当然主要针对的是那些静态使用模式(static usage patterns)的API。
如果我们仅将API与自己的客户端一起使用的话,那么针对固有查询的变化一般不会经常发生。而如果我们的API需要处理不同客户端的不同请求,那么查询请求不但多,而且杂。这些只有细微差别的请求往往会拖慢整体的速度。而消除此类问题的一种做法是:检查那些最常见的查询,并对它们实施综合监控。这就意味着我们需要事先定义一整套查询和变量的组合,然后从测试客户端运行之,以获悉它们的用时。在此基础上,我们能够减少在更新时产生的,严重影响性能的风险因素。由于持久化查询(Persisted queries,https://blog.apollographql.com/persisted-graphql-queries-with-apollo-client-119fd7e6bba5)可以缓存那些最常用的查询,因此我们可以用它来解决此类问题。
3. 解析器和数据加载器
如果我们能够查看到后端所访问的数据源位置,那么就能够更好地获悉如下方面:
- 是在访问模式中使用了错误的数据源,还是需要改用其他类型的数据库?
- 如果数据源类型没问题的话,那么我们还需要改进对它们的请求方式吗?我们是否需要添加数据加载器?
- 那些发送到外部API的请求是否太慢了?我们是否可以将数据复制到更接近后端的位置?
可见,只有当我们能够看到后端具体查询的是什么数据时,上述问题的答案才能迎刃而解。
正如我们在前面讨论过的:解析器只能允许我们监控单个解析器的运作;而数据加载器使我们能够在一个请求中查看到所有解析器的工作。那么,数据加载器的另一个附带好处便是:我们能够发现解析器之间的问题,并及时予以解决。
4. 全栈跟踪
最为全面透彻的监控方式当属:使用tracing-ID来标记查询,将其传递给解析器以完成对该ID的解析,然后传递给数据加载器,并最终抵达数据源本身。据此,我们可以使用tracing-ID来记录时间和错误,以便后续对其进行合并,以及了解局部状态。
当然,在测量查询时,我们所获取到的有关解析用时的数据,实际上是数据被加载到解析器和/或数据加载器中进行的,而不是完成查询解析的用时。毕竟,系统在加载数据时,已不再需要使用查询了。这也就是GraphQL的核心思想之一:将查询与实际数据的加载进行解耦(decoupling)。可见,我们通过全栈监控,可以全面地获悉在发送查询时,后台究竟是如何运作的。
结论
总的说来,通过了解GraphQL API的后端结构,我们可以将REST API挂接到目标代码的不同位置,进而清晰且全面地监控生产系统,以获悉有关缓存和错误处理等方面的问题。
原How to Best Monitor GraphQL APIs ,作者: Kay Ploesser
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】