GraphQL和微服务架构


175

我试图了解GraphQL在微服务体系结构中最适合使用的地方。

关于仅使用1个GraphQL模式作为API网关将请求代理到目标微服务并强制其响应的问题,存在一些争论。微服务仍将使用REST / Thrift协议进行通信。

相反,另一种方法是每个微服务具有多个GraphQL模式。拥有一个较小的API网关服务器,该服务器使用请求的所有信息+ GraphQL查询将请求路由到目标微服务。

第一种方法

具有1个GraphQL架构作为API网关将具有一个缺点,即每次您更改微服务合同的输入/输出时,我们都必须在API网关侧相应地更改GraphQL架构。

第二种方法

如果每个微服务使用多个GraphQL架构,则以某种方式有意义,因为GraphQL会强制执行架构定义,并且使用者将需要尊重微服务提供的输入/输出。

问题

  • 您是否认为GraphQL适合设计微服务架构?

  • 您如何设计具有可能的GraphQL实现的API网关?

Answers:


240

绝对方法#1。

首先,让您的客户与多个GraphQL服务进行对话(如方法2)完全无法达到使用GraphQL的目的,即提供整个应用程序数据的架构,以允许在一次往返中获取它。

拥有一个无共享架构似乎是合理的从微服务的角度,而是为你的客户端代码这是一个绝对的噩梦,因为每次你改变你的微服务之一,你必须更新所有你的客户。您一定会后悔的。

GraphQL和微服务非常适合,因为GraphQL隐藏了客户端具有微服务架构的事实。从后端的角度来看,您希望将所有内容拆分为微服务,但是从前端的角度来看,您希望所有数据都来自单个API。使用GraphQL是我所知道的最好的方法,可以让您同时执行这两项操作。它使您可以将后端划分为微服务,同时仍为所有应用程序提供单个API,并允许跨不同服务的数据进行联接。

如果您不想对REST使用REST,那么当然可以让它们每个都有自己的GraphQL API,但是您仍然应该有一个API网关。人们使用API​​网关的原因是使从客户端应用程序调用微服务变得更易于管理,而不是因为它非常适合微服务模式。


2
@helfer:这真的很有意义:)谢谢。除了这个华丽的答案之外,我还有几个问题。-您是说GraphQL必须用作API网关?-假设我有一个Order Microservice,它公开了REST或GraphQL端点。完成后,我必须更新主GraphQL模式以反映微服务将公开的完全相同的数据?听起来不是重复的做法,还是摆脱了应该独立部署的微服务文化?对微服务的任何更改都必须反映/复制到主GraphQL模式中?
Fabrizio Fenoglio

13
@Fabrizio GraphQL的好处是,即使后端REST API发生了变化,只要有一种获取REST服务先前公开的数据的方法,GraphQL架构仍可以保持不变。如果它公开了更多的数据,那么处理该问题的规范方法就是将新的字段/类型添加到现有架构中。创建GraphQL的Facebook人士告诉我,他们四年来从未对其架构进行过重大更改。他们所做的所有更改都是累加的,这意味着新客户端可以使用新功能,而旧客户端可以继续使用。
Helfer

4
对!:)感谢您写下来!我正在通过apollo repos在Medium和github上关注您!您的文章和帖子非常有价值!:) 保持良好的工作!我还认为阅读GraphQL + Microservices主题的中篇文章将非常有趣!
Fabrizio Fenoglio

1
谢谢,我会记住这一点。绝对计划在某个时候写有关GraphQL和微服务的文章,但可能不会在接下来的几周内写。
Helfer '16

选项#2和github.com/AEB-labs/graphql-weaver的组合怎么
Mohsen

35

请参阅此处的文章,其中说明了方法1的工作原理和效果。还要看下面从我提到的文章中获得的图像: 在此处输入图片说明

将所有内容都放在单个端点后面的主要好处之一是,与每个请求都有自己的服务相比,可以更有效地路由数据。尽管这是GraphQL经常被吹捧的价值,它减少了复杂性并降低了服务蠕变,但所得的数据结构还允许对数据所有权进行非常好的定义,并清楚地进行描述。

采用GraphQL的另一个好处是,您可以从根本上断言可以更好地控制数据加载过程。因为数据加载器的过程进入其自己的端点,所以您可以部分,完全或以警告的形式满足请求,从而以极其精细的方式控制数据的传输方式。

以下文章很好地解释了这两个好处:https : //nordicapis.com/7-unique-benefits-of-using-graphql-in-microservices/


嗨,抱歉,没有菜鸟问题,但是您的graphQL网关不是新的保留点吗?例如,如果我的购物篮服务突然变得过客,我的graphQL网关也不会中断吗?基本上我不确定它的作用,这个网关应该为每个服务包含很多解析器?
Eric Burel

1
@EricBurel感谢您的问题。实际上,据我从本文了解到的那样,来自不同服务的所有模式都统一在一个GraphQL模式下,因此,正如您所提到的,其他服务仍驻留在它们自己的数据集上。关于graphQL网关单一故障源的可能性,总是有其他选择,例如提供备份计划。请阅读本文(labs.getninjas.com.br/…)了解更多信息。希望这可以帮助。
Enayat

您如何测试中央API网关和各个服务?您正在整合还是嘲笑http响应?
Jaime Sangcap

7

对于方法2,实际上是我选择的方法,因为它比手动维护烦人的API网关要容易得多。通过这种方式,您可以独立开发服务。让生活更轻松:P

有一些很棒的工具可以将模式组合为一个,例如graphql-weaver和apollo的graphql-tools,我正在使用graphql-weaver,它易于使用并且效果很好。


我必须在所有查询中创建一个.graphql文件,以便在Android中使用GraphQL吗?还是我可以不使用此文件而直接在代码中创建它们?
MauroAlexandro

1
@MauroAlexandro我不是一个机器人人,但是您可以在不同文件中进行查询。这更多是一个设计问题。恕我直言,我更喜欢第一个:)
HFX

5

截至2019年中,第一种方法的解决方案现在由阿波罗人创造(以前通常称为GraphQL缝合),名称为“ Schema Federation ” 。他们还提出了模块及这一点。@apollo/federation@apollo/gateway

添加:请注意,使用Schema Federation,您不能在网关级别修改架构。因此,对于架构中需要的每一点,都需要有一个单独的服务。


知道此解决方案需要Apollo Server也很有效,Apollo Server的免费版本略有限制(每月最多2500万次查询)
马克思

0

截至2019年,最好的方法是编写实现阿波罗网关规范的微服务,然后按照方法1使用网关将这些服务粘合在一起。建立网关的最快方式是像搬运工图像这一个 ,然后使用泊坞窗,撰写以同时启动所有的服务:

version: '3'

services:
    service1:
        build: service1
    service2:
        build: service2
    gateway:
        ports:
            - 80:80
        image: xmorse/apollo-federation-gateway
        environment: 
            - CACHE_MAX_AGE=5
            - "FORWARD_HEADERS=Authorization, X-Custom-Header" # default is Authorization, pass '' to reset
            - URL_0=http://service1
            - URL_1=http://service2

0

在此问题中,它的描述方式相信,将自定义API网关用作编排服务对于以企业为中心的复杂应用程序很有意义。至少就查询而言,GraphQL可以成为该编排服务的良好技术选择。第一种方法(所有微服务的一个架构)的优点是能够在单个请求中将来自多个微服务的数据缝合在一起。根据您的情况,这可能非常重要,也可能不会非常重要。如果GUI一次要求从多个微服务渲染数据,则此方法可以简化客户端代码,以便单个调用可以返回适合与Angular或React这样的框架的GUI元素进行数据绑定的数据。此优势不适用于突变。

缺点是数据API和业务流程服务之间紧密耦合。发布不再是原子的。如果您不打算在数据API中引入向后突破性的更改,那么只有回滚发行版时,这才可能带来复杂性。例如,如果您将要发布两个数据API的新版本,并在业务流程服务中进行了相应的更改,并且您需要回滚其中一个版本,而不要回滚另一个版本,那么无论如何您都将不得不回滚这三个版本。

GraphQL与REST的比较中,您会发现GraphQL不如RESTful API高效,因此我不建议您为数据API用GraphQL代替REST。


0

对于问题1,Intuit几年前宣布迁移到一个Intuit API生态系统时就承认GraphQL的强大功能(https://www.slideshare.net/IntuitDeveloper/building-the-next-generation-of-quickbooks-app-integrations -quickbooks-connect-2017)。Intuit选择采用方法1。您提到的缺点实际上阻止了开发人员引入可能会破坏客户端应用程序的重大架构更改。

GraphQL通过多种方式帮助提高了开发人员的生产力。

  1. 在为域设计新的微服务时,工程师(后端/前端/利益相关者)同意域实体的架构。架构被批准后,将与主域架构(通用)合并并部署在网关上。前端工程师可以使用此架构开始对客户端应用程序进行编码,而后端工程师可以实现该功能。具有一个通用模式意味着没有两个具有冗余功能的微服务。
  2. GraphQL帮助客户应用程序变得更简单,更快。是否想从/ update数据中检索数据到多个微服务?所有客户端应用程序必须执行的是发出一个GraphQL请求,并且API网关抽象层将注意从多个源(微服务)中获取和整理数据。像Apollo(https://www.apollographql.com/)这样的开源框架加快了GraphQL的采用速度。

  3. 由于移动设备是现代应用程序的首选,因此从零接地开始设计以降低数据带宽需求非常重要。GraphQL通过允许客户端应用程序仅请求特定字段来提供帮助。

问题2:我们在API网关上构建了一个自定义抽象层,该抽象层知道模式的哪一部分归哪个服务(提供者)所有。当查询请求到达时,抽象层将请求转发到适当的服务。基础服务返回响应后,抽象层负责返回请求的字段。

但是,今天有几种平台(Apollo服务器,graphql-yoga等)允许一个平台立即构建GraphQL抽象层。


0

我一直在使用GraphQL和微服务

根据我的经验,对我有用的是根据功能/用途将这两种方法结合使用,我将永远不会像方法1那样拥有单个网关...但是对于每个微服务来说,graphql就像方法2一样。

例如,基于来自Enayat的答案的图像,在这种情况下,我要做的是拥有3个图形网关(而不是图像中的5个)

在此处输入图片说明

  • 应用程序(产品,购物篮,运输,库存,需要/链接到其他服务)

  • 付款

  • 用户

这样,您需要特别注意从相关服务公开的所需/链接的最小数据的设计,例如身份验证令牌,用户标识,付款标识,付款状态

以我的经验为例,我有“用户”网关,在GraphQL中,我有用户查询/更改,登录,登录,注销,更改密码,恢复电子邮件,确认电子邮件,删除帐户,编辑个人资料,上传图片,等等...这个图本身就很大!之所以分开,是因为其他服务/网关最后只关心结果信息,例如用户ID,名称或令牌。

这样更容易...

  • 根据不同的网关规模缩放/关闭它们。(例如,人们可能并不总是在编辑个人资料或付款...,但是搜索产品的频率可能会更高)。

  • 网关成熟,增长,用途已知或您在域上拥有更多专业知识之后,您就可以确定哪些模式可以拥有自己的网关(...发生在我身上的是与git存储库交互的巨大模式,我分离了与存储库交互的网关,发现唯一需要输入/链接的信息是...文件夹路径和期望的分支)

  • 您的存储库的历史更加清晰,您可以拥有一个专门用于网关及其所涉及的微服务的存储库/开发人员/团队。

更新:

我有一个在线的kubernetes集群,该集群使用的是我在此描述的相同方法以及所有使用GraphQL的后端(所有开源),这是主要的存储库:https : //github.com/vicjicaman/microservice-realm

这是对我的答案的更新,因为我认为最好将答案/方法备份为正在运行并且可以查阅/查看的代码,希望对您有所帮助。


-3

由于微服务架构没有适当的定义,因此没有这种样式的特定模型,但是其中大多数都没有明显的特征。在微服务架构的情况下,每个服务都可以分解为单独的小组件,这些小组件可以单独调整和部署,而不会影响应用程序的完整性。这意味着您可以简单地更改一些服务,而无需通过自定义微服务应用程序开发进行应用程序重新部署。


即使缺乏“适当的定义”,它也是一个很好理解的概念,并且在问题中明确标出。除此之外,您的答案根本无法解决问题。
罗伊·普林斯

-7

关于微服务,我认为GraphQL也可以在无服务器架构中完美运行。我不使用GraphQL,但是我有自己的类似项目。我将其用作聚合器,该聚合器调用并将许多功能集中到单个结果中。我认为您可以对GraphQL应用相同的模式。


2
抱歉,但这与OP的问题完全无关。问题是关于使用GraphQL的两种特定方法。最好将其添加为评论。
tiomno
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.