何时以及如何将 GraphQL 与微服务架构一起使用
When and How to use GraphQL with microservice architecture
我正在尝试了解 GraphQL 最适合在微服务架构中的哪些地方使用。
关于只有 1 个 GraphQL 模式作为 API 网关将请求代理到目标微服务并强制其响应存在一些争论。微服务仍然会使用 REST / Thrift 协议进行通信。
另一种方法是为每个微服务提供多个 GraphQL 模式。拥有一个较小的 API 网关服务器,将请求路由到目标微服务,其中包含请求的所有信息 + GraphQL 查询。
第一种方法
将 1 个 GraphQL Schema 作为 API 网关会有一个缺点,即每次更改微服务合同时 input/output,我们都必须在 API 上相应地更改 GraphQL Schema网关端。
第二种方法
如果每个微服务使用多个 GraphQL 模式,这在某种程度上是有意义的,因为 GraphQL 强制执行模式定义,并且消费者需要尊重微服务提供的 input/output。
问题
您在哪里发现 GraphQL 最适合设计微服务架构?
您将如何设计具有可能的 GraphQL 实现的 API 网关?
绝对接近 #1。
让你的客户与多个 GraphQL 服务对话(如方法 #2)完全违背了使用 GraphQL 的初衷,即为你的 整个[=23= 提供一个模式] 应用程序数据,以允许在单次往返中获取它。
什么都不共享架构从微服务的角度来看似乎是合理的,但对于您的客户端代码来说,这绝对是一场噩梦,因为每次您更改一个微服务时,您必须更新 all 个客户。你一定会后悔的。
GraphQL 和微服务是绝配,因为 GraphQL 向客户端隐藏了您拥有微服务架构的事实。从后端的角度来看,您希望将所有内容拆分为微服务,但从前端的角度来看,您希望所有数据都来自一个 API。使用 GraphQL 是我所知道的最好的方式,它可以让你同时做到这两点。它允许您将后端拆分为微服务,同时仍然为所有应用程序提供单个 API,并允许连接来自不同服务的数据。
如果您不想为您的微服务使用 REST,您当然可以让每个微服务都有自己的 GraphQL API,但您仍然应该有一个 API 网关。人们使用 API 网关的原因是为了更易于管理从客户端应用程序调用微服务,而不是因为它非常适合微服务模式。
对于方法 #2,实际上这是我选择的方式,因为它比手动维护烦人的 API 网关容易得多。通过这种方式,您可以独立开发您的服务。让生活更轻松 :P
有一些很棒的工具可以将模式合并为一个,例如graphql-weaver and apollo's graphql-tools,我正在使用 graphql-weaver
,它易于使用且效果很好。
This article 推荐方法 #1。也请参见下图,摘自上述文章:
将所有内容都放在一个端点后面的主要好处之一是,与每个请求都有自己的服务相比,可以更有效地路由数据。虽然这是 GraphQL 经常被吹捧的价值,降低了复杂性和服务蠕变,但由此产生的数据结构也允许数据所有权得到非常明确的定义,并清楚地描述。
采用 GraphQL 的另一个好处是,您可以从根本上更好地控制数据加载过程。由于数据加载器的进程进入其自己的端点,您可以部分、完全或有警告地接受请求,从而以极其精细的方式控制数据的传输方式。
以下文章很好地解释了这两个好处以及其他好处:https://nordicapis.com/7-unique-benefits-of-using-graphql-in-microservices/
截至 2019 年年中,第一种方法 的解决方案现已命名为“Schema Federation" coined by the Apollo people(以前这通常称为 GraphQL 拼接)。
他们还为此提出了模块 @apollo/federation
和 @apollo/gateway
。
添加:请注意,使用架构联合,您无法在网关级别修改架构。因此,对于架构中需要的每一位,您都需要有一个单独的服务。
我一直在使用 GraphQL 和微服务
根据我的经验,对我有用的是两种方法的组合,具体取决于 functionality/usage,我永远不会像方法 1 那样拥有单个网关,但也不会像方法 2 那样为每个微服务使用 GraphQL .
例如,根据 Enayat 回答的图像,在这种情况下我要做的是拥有 3 个图形网关(不是图像中的 5 个)
应用程序(产品、购物篮、运输、库存,needed/linked 到其他服务)
付款
用户
通过这种方式,您需要特别注意 needed/linked 从相关服务公开的最少数据的设计,例如身份验证令牌、用户 ID、付款 ID、付款状态
例如,根据我的经验,我有“用户”网关,在那个 GraphQL 中我有用户 queries/mutations、登录、登录、注销、更改密码、恢复电子邮件、确认电子邮件、删除帐户、编辑个人资料、上传图片等...这个图本身就很大!,它被分开是因为最后另一个 services/gateways 只关心结果信息,如用户 ID、名称或令牌。
这种方式更容易...
Scale/shutdown 不同的网关节点取决于它们的用途。 (例如,人们可能并不总是在编辑他们的个人资料或付款......但可能会更频繁地使用搜索产品)。
一旦网关成熟、成长、使用已知或您在该领域拥有更多专业知识,您就可以确定哪些是架构的一部分,可以拥有自己的网关(...碰巧我有一个与 git 存储库交互的巨大模式,我将与存储库交互的网关分开,我看到唯一的输入 needed/linked 信息是......文件夹路径和预期分支)
您存储库的历史更加清晰,您可以有一个 repository/developer/team 专用于网关及其涉及的微服务。
更新:
我有一个在线的 kubernetes 集群,它使用的方法与我在此处描述的所有后端都使用 GraphQL,全部开源,这里是主存储库:
https://github.com/vicjicaman/microservice-realm
这是对我的回答的更新,因为我认为如果 answer/approach 的备份代码是 运行 并且可以是 consulted/reviewed 会更好,我希望这个有帮助。
截至 2019 年,最好的方法是编写实现 apollo gateway 规范的微服务,然后按照方法 #1 使用网关将这些服务粘合在一起。
构建网关的最快方法是像 this one 这样的 docker 图像
然后使用docker-compose并发启动所有服务:
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
根据这个问题中描述的方式,我相信使用自定义 API 网关作为编排服务对于复杂的以企业为中心的应用程序非常有意义。 GraphQL 可以成为该编排服务的一个很好的技术选择,至少就查询而言是这样。第一种方法(所有微服务的一个模式)的优点是能够在单个请求中将来自多个微服务的数据拼接在一起。根据您的情况,这可能非常重要,也可能不重要。如果 GUI 一次调用从多个微服务渲染数据,那么这种方法可以简化客户端代码,这样一次调用就可以 return 适合与 [= 等框架的 GUI 元素进行数据绑定的数据17=] 或反应。此优势不适用于突变。
缺点是数据 API 与编排服务之间的紧密耦合。发布不再是原子的。如果您避免在数据 API 中引入向后的重大更改,那么这只会在回滚版本时引入复杂性。例如,如果您要发布两个数据 API 的新版本,并在编排服务中进行相应的更改,并且您需要回滚其中一个版本而不回滚另一个版本,那么您将被迫回滚无论如何都要支持所有三个。
在 GraphQL vs REST 的比较中,您会发现 GraphQL 不如 RESTful APIs 高效,因此我不建议将 REST 替换为 GraphQL 来处理数据 APIs.
关于问题 1,几年前 Intuit 在宣布迁移到 One Intuit API 生态系统 (https://www.slideshare.net/IntuitDeveloper/building-the-next-generation-of-quickbooks-app-integrations-quickbooks-connect-2017) 时承认了 GraphQL 的强大功能。 Intuit 选择采用方法 1。您提到的缺点实际上阻止了开发人员引入可能会破坏客户端应用程序的破坏性架构更改。
GraphQL 以多种方式帮助提高了开发人员的生产力。
- 在为域设计新的微服务时,工程师(后端/前端/利益相关者)就域实体的模式达成一致。一旦架构获得批准,它就会与主域架构(通用)合并并部署在 Gateway.Front 端工程师可以开始使用此架构编写客户端应用程序,同时后端工程师实现功能。拥有一个通用模式意味着没有两个具有冗余功能的微服务。
GraphQL 帮助客户端应用程序变得更简单、更快。想要从/更新数据中检索数据到多个微服务?所有客户端应用程序所要做的就是发出一个 GraphQL 请求,API 网关抽象层将负责从多个来源(微服务)获取和整理数据。像 Apollo (https://www.apollographql.com/) 这样的开源框架加快了 GraphQL 的采用速度。
随着移动成为现代应用程序的首选,从零开始设计以降低数据带宽要求非常重要。 GraphQL 通过允许客户端应用仅请求特定字段来提供帮助。
关于问题 2:我们在 API 网关上构建了一个自定义抽象层,它知道模式的哪一部分由哪个服务(提供者)拥有。当查询请求到达时,抽象层将请求转发给适当的服务。一旦底层服务 return 响应,抽象层就负责 return 请求的字段。
然而,今天有几个平台(Apollo 服务器、graphql-yoga 等)允许人们立即构建 GraphQL 抽象层。
我们对 bootstrap 使用 graphql 构建微服务生态系统也有类似的担忧。我们可以使用 Apollo GraphQL 来解决它。
我们为 One Platform
从头开始构建这些解决方案。以 service 结尾的文件夹是微服务,其他是 SPA 又名(单页应用程序)
它由各种微服务和 SPA 组成,API Gateway 是多个微服务的主要接口。
除此之外,您还可以找到 OP CLI generator,它可以帮助从头开始 bootstrap 微服务。
项目 - https://github.com/1-Platform/one-platform
我请求看看这个项目,如果你觉得不错,请随时采纳。
此致
我正在尝试了解 GraphQL 最适合在微服务架构中的哪些地方使用。
关于只有 1 个 GraphQL 模式作为 API 网关将请求代理到目标微服务并强制其响应存在一些争论。微服务仍然会使用 REST / Thrift 协议进行通信。
另一种方法是为每个微服务提供多个 GraphQL 模式。拥有一个较小的 API 网关服务器,将请求路由到目标微服务,其中包含请求的所有信息 + GraphQL 查询。
第一种方法
将 1 个 GraphQL Schema 作为 API 网关会有一个缺点,即每次更改微服务合同时 input/output,我们都必须在 API 上相应地更改 GraphQL Schema网关端。
第二种方法
如果每个微服务使用多个 GraphQL 模式,这在某种程度上是有意义的,因为 GraphQL 强制执行模式定义,并且消费者需要尊重微服务提供的 input/output。
问题
您在哪里发现 GraphQL 最适合设计微服务架构?
您将如何设计具有可能的 GraphQL 实现的 API 网关?
绝对接近 #1。
让你的客户与多个 GraphQL 服务对话(如方法 #2)完全违背了使用 GraphQL 的初衷,即为你的 整个[=23= 提供一个模式] 应用程序数据,以允许在单次往返中获取它。
什么都不共享架构从微服务的角度来看似乎是合理的,但对于您的客户端代码来说,这绝对是一场噩梦,因为每次您更改一个微服务时,您必须更新 all 个客户。你一定会后悔的。
GraphQL 和微服务是绝配,因为 GraphQL 向客户端隐藏了您拥有微服务架构的事实。从后端的角度来看,您希望将所有内容拆分为微服务,但从前端的角度来看,您希望所有数据都来自一个 API。使用 GraphQL 是我所知道的最好的方式,它可以让你同时做到这两点。它允许您将后端拆分为微服务,同时仍然为所有应用程序提供单个 API,并允许连接来自不同服务的数据。
如果您不想为您的微服务使用 REST,您当然可以让每个微服务都有自己的 GraphQL API,但您仍然应该有一个 API 网关。人们使用 API 网关的原因是为了更易于管理从客户端应用程序调用微服务,而不是因为它非常适合微服务模式。
对于方法 #2,实际上这是我选择的方式,因为它比手动维护烦人的 API 网关容易得多。通过这种方式,您可以独立开发您的服务。让生活更轻松 :P
有一些很棒的工具可以将模式合并为一个,例如graphql-weaver and apollo's graphql-tools,我正在使用 graphql-weaver
,它易于使用且效果很好。
This article 推荐方法 #1。也请参见下图,摘自上述文章:
将所有内容都放在一个端点后面的主要好处之一是,与每个请求都有自己的服务相比,可以更有效地路由数据。虽然这是 GraphQL 经常被吹捧的价值,降低了复杂性和服务蠕变,但由此产生的数据结构也允许数据所有权得到非常明确的定义,并清楚地描述。
采用 GraphQL 的另一个好处是,您可以从根本上更好地控制数据加载过程。由于数据加载器的进程进入其自己的端点,您可以部分、完全或有警告地接受请求,从而以极其精细的方式控制数据的传输方式。
以下文章很好地解释了这两个好处以及其他好处:https://nordicapis.com/7-unique-benefits-of-using-graphql-in-microservices/
截至 2019 年年中,第一种方法 的解决方案现已命名为“Schema Federation" coined by the Apollo people(以前这通常称为 GraphQL 拼接)。
他们还为此提出了模块 @apollo/federation
和 @apollo/gateway
。
添加:请注意,使用架构联合,您无法在网关级别修改架构。因此,对于架构中需要的每一位,您都需要有一个单独的服务。
我一直在使用 GraphQL 和微服务
根据我的经验,对我有用的是两种方法的组合,具体取决于 functionality/usage,我永远不会像方法 1 那样拥有单个网关,但也不会像方法 2 那样为每个微服务使用 GraphQL .
例如,根据 Enayat 回答的图像,在这种情况下我要做的是拥有 3 个图形网关(不是图像中的 5 个)
应用程序(产品、购物篮、运输、库存,needed/linked 到其他服务)
付款
用户
通过这种方式,您需要特别注意 needed/linked 从相关服务公开的最少数据的设计,例如身份验证令牌、用户 ID、付款 ID、付款状态
例如,根据我的经验,我有“用户”网关,在那个 GraphQL 中我有用户 queries/mutations、登录、登录、注销、更改密码、恢复电子邮件、确认电子邮件、删除帐户、编辑个人资料、上传图片等...这个图本身就很大!,它被分开是因为最后另一个 services/gateways 只关心结果信息,如用户 ID、名称或令牌。
这种方式更容易...
Scale/shutdown 不同的网关节点取决于它们的用途。 (例如,人们可能并不总是在编辑他们的个人资料或付款......但可能会更频繁地使用搜索产品)。
一旦网关成熟、成长、使用已知或您在该领域拥有更多专业知识,您就可以确定哪些是架构的一部分,可以拥有自己的网关(...碰巧我有一个与 git 存储库交互的巨大模式,我将与存储库交互的网关分开,我看到唯一的输入 needed/linked 信息是......文件夹路径和预期分支)
您存储库的历史更加清晰,您可以有一个 repository/developer/team 专用于网关及其涉及的微服务。
更新:
我有一个在线的 kubernetes 集群,它使用的方法与我在此处描述的所有后端都使用 GraphQL,全部开源,这里是主存储库: https://github.com/vicjicaman/microservice-realm
这是对我的回答的更新,因为我认为如果 answer/approach 的备份代码是 运行 并且可以是 consulted/reviewed 会更好,我希望这个有帮助。
截至 2019 年,最好的方法是编写实现 apollo gateway 规范的微服务,然后按照方法 #1 使用网关将这些服务粘合在一起。 构建网关的最快方法是像 this one 这样的 docker 图像 然后使用docker-compose并发启动所有服务:
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
根据这个问题中描述的方式,我相信使用自定义 API 网关作为编排服务对于复杂的以企业为中心的应用程序非常有意义。 GraphQL 可以成为该编排服务的一个很好的技术选择,至少就查询而言是这样。第一种方法(所有微服务的一个模式)的优点是能够在单个请求中将来自多个微服务的数据拼接在一起。根据您的情况,这可能非常重要,也可能不重要。如果 GUI 一次调用从多个微服务渲染数据,那么这种方法可以简化客户端代码,这样一次调用就可以 return 适合与 [= 等框架的 GUI 元素进行数据绑定的数据17=] 或反应。此优势不适用于突变。
缺点是数据 API 与编排服务之间的紧密耦合。发布不再是原子的。如果您避免在数据 API 中引入向后的重大更改,那么这只会在回滚版本时引入复杂性。例如,如果您要发布两个数据 API 的新版本,并在编排服务中进行相应的更改,并且您需要回滚其中一个版本而不回滚另一个版本,那么您将被迫回滚无论如何都要支持所有三个。
在 GraphQL vs REST 的比较中,您会发现 GraphQL 不如 RESTful APIs 高效,因此我不建议将 REST 替换为 GraphQL 来处理数据 APIs.
关于问题 1,几年前 Intuit 在宣布迁移到 One Intuit API 生态系统 (https://www.slideshare.net/IntuitDeveloper/building-the-next-generation-of-quickbooks-app-integrations-quickbooks-connect-2017) 时承认了 GraphQL 的强大功能。 Intuit 选择采用方法 1。您提到的缺点实际上阻止了开发人员引入可能会破坏客户端应用程序的破坏性架构更改。
GraphQL 以多种方式帮助提高了开发人员的生产力。
- 在为域设计新的微服务时,工程师(后端/前端/利益相关者)就域实体的模式达成一致。一旦架构获得批准,它就会与主域架构(通用)合并并部署在 Gateway.Front 端工程师可以开始使用此架构编写客户端应用程序,同时后端工程师实现功能。拥有一个通用模式意味着没有两个具有冗余功能的微服务。
GraphQL 帮助客户端应用程序变得更简单、更快。想要从/更新数据中检索数据到多个微服务?所有客户端应用程序所要做的就是发出一个 GraphQL 请求,API 网关抽象层将负责从多个来源(微服务)获取和整理数据。像 Apollo (https://www.apollographql.com/) 这样的开源框架加快了 GraphQL 的采用速度。
随着移动成为现代应用程序的首选,从零开始设计以降低数据带宽要求非常重要。 GraphQL 通过允许客户端应用仅请求特定字段来提供帮助。
关于问题 2:我们在 API 网关上构建了一个自定义抽象层,它知道模式的哪一部分由哪个服务(提供者)拥有。当查询请求到达时,抽象层将请求转发给适当的服务。一旦底层服务 return 响应,抽象层就负责 return 请求的字段。
然而,今天有几个平台(Apollo 服务器、graphql-yoga 等)允许人们立即构建 GraphQL 抽象层。
我们对 bootstrap 使用 graphql 构建微服务生态系统也有类似的担忧。我们可以使用 Apollo GraphQL 来解决它。
我们为 One Platform
从头开始构建这些解决方案。以 service 结尾的文件夹是微服务,其他是 SPA 又名(单页应用程序)
它由各种微服务和 SPA 组成,API Gateway 是多个微服务的主要接口。
除此之外,您还可以找到 OP CLI generator,它可以帮助从头开始 bootstrap 微服务。
项目 - https://github.com/1-Platform/one-platform
我请求看看这个项目,如果你觉得不错,请随时采纳。
此致