GraphQL—构建多服务架构的数据层

2023-11-24 17:15:47 浏览数 (2)

简介

作为 Facebook 在 2015 年推出的查询语言,GraphQL 能够对 API 中的数据提供一套易于理解的完整描述,使得客户端能够更加准确的获得它需要的数据

现在的web系统大多是基于restful的,我们知道,REST强调以资源来划分系统,通过URL规范来操作相应的资源:

  • 一个系统中的资源有关联关系,通过URL规范就不太好定义一个很好的url接口
  • 每个操作都需要对应一个url接口
  • 前端在获取资源组合的数据展示时,需要请求好几个接口,然后自行组装数据

GraphQL则不同,它具有强大的表达能力,这主要还是来自于它完备的类型系统,它将整个 Web 服务中的全部资源看成一个有连接的图,而不是一个个资源孤岛,在访问任何资源时都可以通过资源之间的连接访问其它的资源。 GraphQL对外只提供一个接口,通过这个接口的body查询字段来灵活的获取各种数据。

Relay规范

GraphQL有自己的规范定义,用于制定一些通用的规则,称为Relay:

  • 提供能够重新获取对象的机制;
  • 提供对如何对连接进行分页的描述;
  • 标准化 mutation 请求,使它们变得更加可预测;

这些规范用来指导GraphQL服务器的实现

Schema

Schema 是任何 GraphQL 服务器实现的核心。它描述了连接到它的客户端应用程序可用的功能。我们可以使用任何编程语言来创建 GraphQL Schema 并围绕它构建一个接口。

GraphQL 运行时定义了一个通用的基于图的模式来发布它所代表的数据服务的功能。客户端应用程序可以在其能力范围内查询Schema。这种方法将客户端与服务器分离,并允许两者独立发展和扩展。

另外,在微服务架构下,多个微服务提供 Schema 时,我们需要通过一种机制将多个服务的 Schema 整合起来,这种整合 Schema 的思路最重要的就是需要解决服务之间的重复资源和冲突字段问题,如果多个服务需要同时提供同一个类型的基础资源

示例

下面我们通过这个在线网站来试用下GraphQL:https://swapi-graphql.netlify.app/?query={ person(personID: 1) { name } }

查询 personID 为 1 的 Person 并且只获取 name,gender 字段 查询条件:

代码语言:javascript复制
{
  person(personID: 1) {
    name,
    gender
  }
}

结果输出:

代码语言:javascript复制
{
  "data": {
    "person": {
      "name": "Luke Skywalker",
      "gender": "male"
    }
  }
}

从上面查询案例中其实就可以发现,我只需要在 person 中写上想要获取的字段,GraphQL 便会返回带有该字段的数据。避免了返回结果中不必要的数据字段。

代码语言:javascript复制
{
    person{ 
        # 写上想获取的字段 
    }
}

如果想要其他其他的数据,不用像 Restful API 那样请求多条接口,依旧请求/graphql: 输入条件:

代码语言:javascript复制
{
  person(personID: 1) {
    id,
    name,
    gender
  },
  planet(planetID:2) {
    id,
    name
  }
}

结果输出:

代码语言:javascript复制
{
  "data": {
    "person": {
      "id": "cGVvcGxlOjE=",
      "name": "Luke Skywalker",
      "gender": "male"
    },
    "planet": {
      "id": "cGxhbmV0czoy",
      "name": "Alderaan"
    }
  }
}

从上面可以看出,GraphQL的查询语句有几个特性:

  • 按需取字段,不需要的字段可以不查询,类似于 SQL 里的 select
  • 在类型定义的基础上,可以关联查询多个类型的数据,类似于 SQL 里的 join(但不完全一样)
  • 可以递归的对某些字段进行理论上无限深度的查询

注意

把 GraphQL 当做一个网关来处理,负责对接底层的微服务。在一些 GraphQL 应用的场景里,随着接入的业务越来越多,GraphQL 的服务会逐步的变成一个非常庞大的单体应用,维护起来会越来越困难。另外所有的业务都聚合到这一个 GraphQL 的出口,可能光 Schema 定义就需要上万行。这样不论是维护还是使用上都很难进行下去,而且与现在主流的微服务架构体系相矛盾

业界目前最主流的解决方案是 Apollo GraphQL 提供的 GraphQL Federation 功能,并且 Netflix 在此基础上构建了一套 DGS (Domain GraphQL Service) 的架构来进行治理的

Golang实践

这里就不具体描述了,可以参考如下两个链接: https://www.apollographql.com/blog/graphql/golang/using-graphql-with-golang/ https://github.com/graphql-go/graphql/tree/master

https://zhuanlan.zhihu.com/p/460593348 https://draveness.me/graphql-microservice/

0 人点赞