利用 Fastify 框架打造 GraphQL 服务器性能测试指南

GraphQL 是现代 Web 开发中不可忽视的技术之一,它可以简化前端和后端之间的数据交互流程,提高客户端与服务器之间的性能效率,同时也能让前端工程师在进行数据请求时更加自由和灵活。

但是,当我们在项目中使用了 GraphQL 技术之后,性能测试就显得尤为重要。因为一个好的性能测试结果不仅能够检测出 GraphQL 服务器中的潜在问题,还能够帮助我们对系统性能做出实际的改进。

此文将介绍如何利用 Fastify 框架打造 GraphQL 服务器性能测试指南来深入了解 GraphQL 服务器的性能,并通过优化代码和执行指标来提升服务器性能。

什么是 Fastify 框架?

Fastify 是一个快速且低开销的 Web 框架,它具有出色的性能和强大的生态,能够处理高流量的服务器请求,因此被广泛用于企业、云计算、基础设施等方面。

与其他类似框架相比,Fastify 在执行速度和内存使用方面非常出色。它还提供了最佳实践、插件修复、生命周期钩子等高级功能,使得我们可以快速地编写高效、安全的 Web 应用程序。

针对性能测试的 GraphQL 服务器设计和拓展

我们需要对 GraphQL 服务器进行性能测试,才能确定服务器的瓶颈和限制,然后针对这些瓶颈和限制进行优化,从而提高服务器的性能和稳定性。

设计一个基础的 GraphQL 服务器

让我们开始编写一个基础的 GraphQL 服务器,它将会用指定的端口进行监听,提供一个 GraphQL 服务端点,并且能够返回一些数据。

const fastify = require('fastify');
const { graphql, buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
      hello: String
  }
`);

const root = {
  hello: () => {
    return 'Hello graphql';
  },
};

const app = fastify({ logger: true });

app.all('/graphql', (req, res) => {
  return graphql(schema, req.body.query, root).then((result) =>
    res.send(result)
  );
});

app.listen(3000, (err) => {
  if (err) {
    console.log(err);
    process.exit(1);
  }
  console.log('Server start listen at: http://localhost:3000');
});

这个代码块创建了一个 GraphQL 服务器,并提供一个 hello 的解析器函数。我们可以使用 Postman / GraphiQL 等工具进行请求,在 localhost:3000/graphql 地址下的服务端口中将会返回 "Hello graphql" 的字符串。

向 GraphQL 服务器添加一些关系型数据

我们将向 GraphQL 服务器添加模拟关系型数据的能力。

const { makeExecutableSchema } = require('graphql-tools');


const typeDefs = gql`
type Author {
    id: Int
    name: String
    books: [String]
}
type Query {
    author(id: Int): Author
    authors: [Author]
    book(id: Int): Book
    books: [Book]
}
type Mutation {
    addAuthor(name: String!): Author
    addBook(title: String!, authorId: Int!): Book
}
type Book {
    id: Int
    title: String
    authorId: Int
    author: Author
}
`

然后我们将要写 resolvers 来与 schema 对接:

const resolvers = {
    Query: {
        author: (....) => {....},
        authors: (....) => {....},
        ....
    },
    Mutation: {
        addAuthor: (....) => {....},
        addBook: (....) => {....},
    },
    Author: {
        books: (....) => {....},
    },
    Book: {
        author: (....) => {....},
    },
};

设计 GraphQL 服务器的测试用例

现在我们已经有了一个基于 GraphQL 的服务器,且服务器还支持关系型数据,下一步需要做的就是为这个服务器设计性能测试用例。

测试用例通过测试某个系统的性能,以确定它能够给出的响应时间、最大峰值用户数等。我们需要以下 3 个元素来设计 GraphQL 服务器的测试用例:

  1. 数据模型:模拟数据模型,以模拟真实世界的数据请求和响应。
  2. 请求负载:用于向服务器发送一定量和一定类型的请求负载,可以使用压力测试工具来模拟请求负载。
  3. 响应时间:针对服务器响应时间的基准值,测试用例在这个基准值上进行测试。

数据模型

为了创建性能测试用例,我们需要创建数据模型并进行测试。这里我们创建一个带 AuthorBook 对象的 GraphQL 模型,其中 Author 拥有 idnamebooks 属性,Book 拥有 idtitleauthorIdauthor 属性:

const schema = buildSchema(`
  type Author {
      id: Int
      name: String
      books: [Book]
  }
  
  type Book {
      id: Int
      title: String
      authorId: Int
      author: Author
  }
  
  type Query {
      getAuthor(id: Int): Author
      getBook(id: Int): Book
  }
`);

const root = {
  getAuthor: ({ id }) => {
    return mockData.authors.find((author) => author.id === id);
  },
  getBook: ({ id }) => {
    return mockData.books.find((book) => book.id === id);
  },
};

const mockData = {
  authors: [
    { id: 1, name: 'Antoine de Saint-Exupéry' },
    { id: 2, name: 'Gabriel Garcia Marquez' },
    { id: 3, name: 'Franz Kafka' },
  ],
  books: [
    { id: 1, title: 'The Little Prince', authorId: 1 },
    { id: 2, title: 'One Hundred Years of Solitude', authorId: 2 },
    { id: 3, title: 'The Trial', authorId: 3 },
  ],
};

在测试用例中,我们使用 mockData 来模拟服务器中的数据模型。使用这种模拟方法,使我们可以更好地掌握性能测试中的数据模拟。因为真实的数据库和服务器中都会涉及到大量的代码和管理难度。当然,这不是唯一的测试方式,你可以在你的项目中使用真实的数据模型来替代模拟测试模型。

请求负载

GraphQL 客户端通过操作某个特定类型的请求来向服务器发送请求负载。请求负载是由查询字符串、操作名称和操作变量组成的,如下所示:

query {
  getAuthor (id: 1) {
    name
    books {
      title
    }
  }
}

在 GraphQL 服务器中,请求负载通常包含以下内容:

  1. 查询或者变更操作,例如 query, mutation 等。
  2. 对某个特定对象、服务或者数据的查询或者变更。
  3. 一些附加的特定于请求的参数或变量,例如 idname 等。

可以使用 Postman、GraphiQL 或其他 API 测试工具实现请求负载的实体和工作流程。此处我们使用 API 请求工具的 Postman 进行测试:

在上图中,我们可以看到请求负载包含了查询操作、被查询的对象、查询需要的参数等。

响应时间

在计算服务请求的速度时,响应时间是一个关键的指标。响应时间反映了客户端与服务器之间进行通信所需的时间。我们可以使用 Fastify 提供的自带插件 replay 缓存和 rate-limiter 来衡量响应时间,例如,在服务器端添加如下的请求处理函数来返回响应时间:

app.addHook('onSend', (request, reply, payload, next) => {
  const time = process.hrtime(request.req.startAt);
  const responseTime = Math.ceil((time[0] * 1e9 + time[1]) / 1e6);
  reply.header('X-Response-Time', responseTime + 'ms');
  next();
});

在上面的代码中,我们使用 onSend 钩子方法来计算时间差,然后在服务器响应头中添加 X-Response-Time 属性来返回响应时间,接下来我们就可以开始使用这个基础的 GraphQL 服务器,做性能测试实验来深入了解 GraphQL 服务器的性能,进而提高服务器性能。

辅助性能测试

使用 GraphQL 服务器性能测试指南,可以帮助你优化和完善你的 GraphQL 服务器代码。但是,除了服务器端代码之外,我们还可以通过以下方法来完善和优化它。

缓存和内存优化

缓存和内存优化是超出这个文档范围的话题,但是 Fastify 提供了一些内置的插件来帮助缓存和内存消除,包括 fastify-cachingfastify-mongofastify-memcachedfastify-redis 等。因此,我们可以使用这些插件来优化缓存和内存效率、减轻服务器负担,进而提高服务器进展速度和性能。

使用压力测试工具

当我们把基础的 GraphQL 服务器搭建完毕之后,还需要进行压力测试以了解服务器性能。有很多流行的工具来进行 Web 应用程序压力测试,如 Apache JMeter、LoadRunner、Gatling、Postman、Artillery 等。

这里我们使用 Artillery,代码如下:

Artillery 提供大量的配置参数,可以帮助我们快速测试虚拟负载下的服务器性能。在上述配置文件中,我们定义了两个流程:getAuthorgetBook。每个流程包含了请求负载、谓词组合等,例如 flow 的第一步使用了 HTTP GET 请求来模拟 getAuthor 小编的 GET 请求,请求地址如 /graphql?query=query{getAuthor(id:1){id,name,books{id,title}}}

接下来,为了模拟更真实业务的场景,我们将此压力测试配置和 GitHub CI/CD 进行集成。在每次代码提交时启动压力测试,以确保我们的 GraphQL 应用程序可以承受一定程度的请求负载。例如,我们可以创建一个 package.json 文件,编写一个 test 脚本,然后在 GitHub Action 中运行它。

{
  "scripts": {
    "pressure": "artillery run <pathToPressureConfig.js>"
  }
}

在上面的代码中,我们使用 artillery run 命令来初始化压力测试。任何你想要的命令都可以试试,因为 Artillery 几乎可以做任何事。如果成功,服务器将开始按照你定义的配置文件进行测试,直到时间或流量达到你所定义的上限。如果服务器出现等待时间过长或者超出最大并发流量的情况,我们就可以调整服务器设置或改进代码来提高服务器性能和效率。

GraphQL 服务器性能测试总结

在本文中,我们已经针对 Fastify 框架打造 GraphQL 服务器性能测试指南以实现一些较完善和可靠的服务器性能测试方法。通过建立数据模型、请求负载和响应时间测试,我们可以对服务器运行进行校准、缓存和优化,以确保服务器在承受严峻的条件下保持高性能且稳定。如果你在开发 GraphQL 项目,在学习性能测试模式时,也可以参考本文一些内容,以对 GraphQL 服务器的基本性能做出评价和修改,以保证可靠的应用程序性能。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65913166eb4cecbf2d66a777


纠错
反馈