在解析大型数据时,从将解析器的结果返回给客户端的那一刻起,我注意到性能非常慢。
我假设apollo-server迭代我的结果并检查类型..。不管怎样,手术时间太长了。
在我的产品中,我必须同时返回大量的数据,因为它被同时使用,以在UI中绘制一个图表。对于我来说,没有分页选项,我可以在其中切片数据。
我怀疑缓慢来自apollo-server,而不是我的解析器对象创建。
注意,我记录解析器创建对象所需的时间,它的速度,而不是瓶颈。
后来由apollo-server执行的操作,我不知道如何衡量,花费了大量的时间.
现在,我有了一个版本,在这个版本中,我返回一个定制的标量类型JSON,响应要快得多。但我真的更喜欢返回我的Series类型。
我通过查看网络面板来度量这两种类型(Series和JSON)之间的差异。
当金额设置为500,且类型为Series时,则需要~1.5s (即秒)
当金额设置为500,且类型为JSON时,则需要150 is (快速!)
当数量设置为1000,并且类型为Series时,它的速度非常慢.
当数量设置为10000,类型为Series时,我将从内存中提取JavaScript堆(不幸的是,这正是我们在产品中所经历的)
我还将apollo-server性能与express-graphql进行了比较,后者的工作速度更快,但仍不如返回自定义标量JSON的速度快。
当金额设置为500,apollo-server,网络需要1.5s
当金额设置为500,express-graphql时,网络需要800 is
当金额设置为1,000,apollo-server时,网络需要5.4s
当金额设置为1000,express-graphql时,网络占用3.4s
堆叠:
"dependencies": {
"apollo-server": "^2.6.1",
"graphql": "^14.3.1",
"graphql-type-json": "^0.3.0",
"lodash": "^4.17.11"
}“守则”:
const _ = require("lodash");
const { performance } = require("perf_hooks");
const { ApolloServer, gql } = require("apollo-server");
const GraphQLJSON = require('graphql-type-json');
// The GraphQL schema
const typeDefs = gql`
scalar JSON
type Unit {
name: String!
value: String!
}
type Group {
name: String!
values: [Unit!]!
}
type Series {
data: [Group!]!
keys: [Unit!]!
hack: String
}
type Query {
complex: Series
}
`;
const AMOUNT = 500;
// A map of functions which return data for the schema.
const resolvers = {
Query: {
complex: () => {
let before = performance.now();
const result = {
data: _.times(AMOUNT, () => ({
name: "a",
values: _.times(AMOUNT, () => (
{
name: "a",
value: "a"
}
)),
})),
keys: _.times(AMOUNT, () => ({
name: "a",
value: "a"
}))
};
let after = performance.now() - before;
console.log("resolver took: ", after);
return result
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers: _.assign({ JSON: GraphQLJSON }, resolvers),
});
server.listen().then(({ url }) => {
console.log(` Server ready at ${url}`);
});游乐场的gql查询(类型为Series):
query {
complex {
data {
name
values {
name
value
}
}
keys {
name
value
}
}
}Playground的gql查询(针对自定义标量类型JSON):
query {
complex
}下面是一个有用的例子:
https://codesandbox.io/s/apollo-server-performance-issue-i7fk7
任何线索/想法都将不胜感激!
发布于 2019-06-13 07:28:20
有一个相关的未决问题,这里。李拜伦总结得很好:
我认为,这个问题的TL;博士是因为GraphQL有一些开销,而减少这种开销并不简单,完全消除它可能不是一个选择。最终,GraphQL.js仍然负责对返回数据的形状和类型提供API边界保证,而且从设计上讲,它不信任底层系统。换句话说,GraphQL.js执行运行时类型检查和子选择,这是有代价的。
GraphQL提供的好处(验证、子选择等)不可避免地会产生一些开销,因为它们需要对您返回的数据进行额外的处理。不幸的是,这种开销与数据的大小成正比。我想,如果要实现一个支持部分响应的REST端点,并使用Swagger或Joi这样的方法进行响应验证,您可能会遇到类似的问题。
“内存不足的堆”错误的意思就像它说的那样--堆上的内存都快用完了。您可以尝试通过手动增加限制来减轻这种情况。
通常,像这样的大型数据集应该通过实现分页来分解。如果这不是一个选项,那么利用自定义标量将是下一个最好的方法。这种方法的最大缺点是,使用API的客户端将无法请求返回的JSON对象中的特定字段。在修补GraphQL.js之外,没有其他选择来加速响应和减少内存使用。
发布于 2019-06-04 08:31:15
评论摘要
这种数据结构/类型:
id字段);通过这种方式,这个数据集不是graphQL设计的。当然,仍然可以用来获取这些数据,但是应该禁用类型解析/匹配。
使用自定义标量类型 (graphql-type-json)可以是一种解决方案。如果需要某种混合解决方案,可以将Group.values输入为json (而不是整个Series)。如果要使用规范化缓存访问,组仍然应该有一个id字段。
替代方案
您可以使用apollo-link-rest获取‘纯’json数据(文件),使类型解析/匹配只在客户端。
更先进的替代方案
如果您想使用一个graphql端点..。写自己的链接-使用指令-‘要求json,得到打字’-混合以上两个。在rest链接中使用反/序列化器。
在这两种选择中-,你为什么真的需要它?只是为了画画?不值得付出这么多努力。没有分页,但希望是流式(实时更新?)没有游标。通过.加载更多(订阅/轮询)。上一次更新?可行但“感觉不对”。
https://stackoverflow.com/questions/56416447
复制相似问题