首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >阿波罗服务器在解析大型数据时性能缓慢

阿波罗服务器在解析大型数据时性能缓慢
EN

Stack Overflow用户
提问于 2019-06-02 15:31:08
回答 2查看 8.8K关注 0票数 8

在解析大型数据时,从将解析器的结果返回给客户端的那一刻起,我注意到性能非常慢。

我假设apollo-server迭代我的结果并检查类型..。不管怎样,手术时间太长了。

在我的产品中,我必须同时返回大量的数据,因为它被同时使用,以在UI中绘制一个图表。对于我来说,没有分页选项,我可以在其中切片数据。

我怀疑缓慢来自apollo-server,而不是我的解析器对象创建。

注意,我记录解析器创建对象所需的时间,它的速度,而不是瓶颈。

后来由apollo-server执行的操作,我不知道如何衡量,花费了大量的时间.

现在,我有了一个版本,在这个版本中,我返回一个定制的标量类型JSON,响应要快得多。但我真的更喜欢返回我的Series类型。

我通过查看网络面板来度量这两种类型(SeriesJSON)之间的差异。

当金额设置为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

堆叠:

代码语言:javascript
复制
"dependencies": {
  "apollo-server": "^2.6.1",
  "graphql": "^14.3.1",
  "graphql-type-json": "^0.3.0",
  "lodash": "^4.17.11"
}

“守则”:

代码语言:javascript
复制
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):

代码语言:javascript
复制
query {
  complex {
    data {
      name
      values {
        name
        value
      }
    }
    keys {
      name
      value
    }
  }
}

Playground的gql查询(针对自定义标量类型JSON):

代码语言:javascript
复制
query {
  complex
}

下面是一个有用的例子:

https://codesandbox.io/s/apollo-server-performance-issue-i7fk7

任何线索/想法都将不胜感激!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-13 07:28:20

有一个相关的未决问题,这里。李拜伦总结得很好:

我认为,这个问题的TL;博士是因为GraphQL有一些开销,而减少这种开销并不简单,完全消除它可能不是一个选择。最终,GraphQL.js仍然负责对返回数据的形状和类型提供API边界保证,而且从设计上讲,它不信任底层系统。换句话说,GraphQL.js执行运行时类型检查和子选择,这是有代价的。

GraphQL提供的好处(验证、子选择等)不可避免地会产生一些开销,因为它们需要对您返回的数据进行额外的处理。不幸的是,这种开销与数据的大小成正比。我想,如果要实现一个支持部分响应的REST端点,并使用Swagger或Joi这样的方法进行响应验证,您可能会遇到类似的问题。

“内存不足的堆”错误的意思就像它说的那样--堆上的内存都快用完了。您可以尝试通过手动增加限制来减轻这种情况。

通常,像这样的大型数据集应该通过实现分页来分解。如果这不是一个选项,那么利用自定义标量将是下一个最好的方法。这种方法的最大缺点是,使用API的客户端将无法请求返回的JSON对象中的特定字段。在修补GraphQL.js之外,没有其他选择来加速响应和减少内存使用。

票数 14
EN

Stack Overflow用户

发布于 2019-06-04 08:31:15

评论摘要

这种数据结构/类型:

  • 不是个人实体;
  • 只是一系列的分组数据;
  • 不需要正常化;
  • 不会在阿波罗缓存中被正确地标准化(没有id字段);

通过这种方式,这个数据集不是graphQL设计的。当然,仍然可以用来获取这些数据,但是应该禁用类型解析/匹配。

使用自定义标量类型 (graphql-type-json)可以是一种解决方案。如果需要某种混合解决方案,可以将Group.values输入为json (而不是整个Series)。如果要使用规范化缓存访问,组仍然应该有一个id字段。

替代方案

您可以使用apollo-link-rest获取‘纯’json数据(文件),使类型解析/匹配只在客户端。

更先进的替代方案

如果您想使用一个graphql端点..。写自己的链接-使用指令-‘要求json,得到打字’-混合以上两个。在rest链接中使用反/序列化器。

在这两种选择中-,你为什么真的需要它?只是为了画画?不值得付出这么多努力。没有分页,但希望是流式(实时更新?)没有游标。通过.加载更多(订阅/轮询)。上一次更新?可行但“感觉不对”。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56416447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档