引入联合GraphQL以解决系统架构中的问题

随着使用需求的增长,用户群的扩大以及新功能的引入,让工程师按照业务的主要领域进行组织变得不可避免。当这些领域在单个实体(如类、服务、应用程序或代码库)的层面变得过于庞大难以管理时,引入联合GraphQL成为优化系统架构的有效手段。

如果GraphQL还不是您在解决开发周期延迟、团队沟通不畅和错过截止日期方面的利器,请考虑采用它作为引入API的正式约定的简便方式,从而使系统架构和依赖该架构的客户端都受益。

我们已经看到一些公司如IMDb和Netflix开始利用GraphQL联合来实现团队自治,并同时保持大规模流量的处理能力,因此让我们更详细地了解如何实现这一点。

一个示例问题空间

让我们设想一个……比如说,博客平台,并考虑在提供该体验时涉及的主要实体。我们有注册的用户,他们可以创建和发布文章,其他用户会对这些文章进行评论点赞

一个简单的数据模型可能如下:

user: id、name、email、createdAt、updatedAt•article: id、userId、title、body、publishedAt、createdAt、updatedAt•comment: id、userId、articleId、createdAt、updatedAt•favorite: id、userId、articleId、createdAt、updatedAt

请注意,我们可能将favorite作为实体的名称,而不是like,因为LIKE是SQL的关键字,可能会在未来引发问题。

4b450746e7706808cbe049fa0146880c.png

四个表及其关系

单一应用程序方法

考虑如何在持久层处理 API 查询以获取由给定用户创建的所有文章(让我们使用SQL来说明):

SELECT a.id AS articleId, a.title, a.body, a.publishedAt, u.id AS userId, u.name
FROM article a, user u
WHERE a.userId = u.id AND u.id = <user_id>;

然后,我们可以部署一个应用程序或无服务器函数,它以userId为输入,执行上述查询,将结果文章数组格式化为JSON响应,并返回给调用者。

在MVP阶段,这种耦合程度可能还可以接受,小的需求变更可能也会顺利处理:

我们可以添加user.imageUrl并在该查询中返回吗?

我们还可以添加article.seoKeywords吗?

这些变更可能会毫无问题地实现。

假设平台开始获得关注,用户从数百名增加到数十万名(做得很棒!),文章从数千篇增加到数百万篇,同时还有更多评论和点赞。我们可以想象这样的增长将导致我们组织内部的一些专业化,从而形成了处理用户(注册、账户管理、CRM)、内容(文章、审核、策划)和反馈(评论、点赞)的新领域和团队。

但是现在有个问题:用户和内容在最低层面上是相互关联的,更糟糕的是,它们部署在同一个应用程序中。如果用户和内容领域都有新功能要在本次迭代中发布,那么每个团队现在都依赖于彼此在规定的时间内完成开发,因为任何一端的错误都会阻塞另一端的部署。

引入GraphQL

好的,但是GraphQL有什么关系呢,更别说联合GraphQL了?

d9040dce4c01b7a581acdbafef79d7e0.gif

思考,思考,再思考……

最终,为了实现大规模数据服务,关键在于合同。在MVP中,用户和内容之间的合同嵌入在我们的SQL查询中的表JOIN中。这样的合同缺乏灵活性和可扩展性。

让我们试着在堆栈中向更高层次移动,寻找新的合同。也许我们可以有一个UserService类和一个ContentService类,分别查询它们自己的相关信息,并在上游控制器类中将这些查询的结果拼接成出站的文章数组和JSON响应。

ef066d1a945d6e9e303566cb0ad90666.png

在控制器层解决跨领域数据

这样做是更好的,但就开发速度而言,如果这些服务仍然属于同一个应用程序或部署,一个领域中的失败变更仍然会阻塞另一个领域中的成功变更。如果合同能够位于更高层次,那将会更好。

事实证明,GraphQL是声明合同的好方法,因为GraphQL模式本质上是客户端可以请求的内容和服务器将在响应中提供的内容之间的合同,类似于OpenAPI / Swagger文档可以告诉调用者关于REST API的信息

但是,GraphQL的妙处在于我们还可以在一个或多个GraphQL端点之前运行网关,并让它们协同工作,以实现统一的模式。这就是GraphQL联合,如果我们为每个领域分配自己的端点,那么每个团队可以有效地独立扩展、维护和部署合同的各个部分,而不会影响其他团队。

在实践中,我们可以利用Apollo的GraphQL功能来实现一个带有GraphQL联合的系统。具体细节可以留待另一篇文章,但是Apollo联合指南提供了您需要立即开始实施的所有内容。

联合GraphQL方法

4e53a1a6c640553a2dee9e88bc81e8e3.png

通过GraphQL联合实现领域分离

首先,我们需要搭建一个网关服务器,该服务器配置有一个服务列表,即参与组合GraphQL模式的URL数组。在我们的情况下,这意味着为每个领域(用户、内容和反馈)都搭建一个单独的端点。

用户和内容的一些模式片段可能如下所示:

services/user/index.graphql

services/content/index.graphql

然后,每个个别的GraphQL模式,称为子图,都贡献到整体模式中,并可以在网关中访问。但是,真正的魔法发生在我们开始定义这些子图之间类似外键的依赖关系时。

例如,我们有一个Article模式,其中包含一个userId属性。如果我们可以根据来自用户服务的实际User类型定义一个User属性,那将会怎样?例如,用户服务端点定义的User类型,即在用户端点中定义的User类型。

要做到这一点,我们需要围绕Article类型中的外键userId形成一个合同,这样,每次请求Article中的User属性时,网关服务器将从用户服务端点获取User属性,并将其拼接到出站响应中。

extend语法和将相关属性装饰为@external允许我们在用户领域中定义与其他领域类型(如Article)相关的关系。这相当于我们在外键上进行SQL连接,但是在网关层面进行的连接,这已经是我们在后端响应中能够实现的最远的地方了。

services/user/index.graphql

现在,唯一剩下的就是在解析器中处理我们的User属性,我们在输入中给出userId并用它作为查找依据。

services/user/resolver.ts

这意味着在网关的最终合同中,联合GraphQL模式中User和Article的类型如下所示:

实现领域分离

因为用户和内容领域都拥有各自的端点和GraphQL模式,它们各自的团队现在可以独立于彼此进行部署,使得团队更加快速和高效。

现在,仅仅依赖于各自子图中的外键关系,这些关系在网关层面更容易维护。

实现跨领域的蓝图 🥂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/52302.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(六)

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python面试专栏&#xff1a;《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; …

web前端框架Javascript之JavaScript 异步编程史

早期的 Web 应用中&#xff0c;与后台进行交互时&#xff0c;需要进行 form 表单的提交&#xff0c;然后在页面刷新后给用户反馈结果。在页面刷新过程中&#xff0c;后台会重新返回一段 HTML 代码&#xff0c;这段 HTML 中的大部分内容与之前页面基本相同&#xff0c;这势必造成…

vue列表全选反选

1、结果查看 2、 选中时添加样式 3、点击选择调用方法 4、全选反选调用方法

“ARTS挑战:探索技术,分享思考“

文章目录 前言一、学习的内容二、遇到的困难及解决办法三、学习打卡成果展示四、学习技巧的总结五、未来学习打卡计划后记 关于 ARTS 的释义 ● Algorithm: 每周至少做一个 LeetCode 的算法题 ● Review: 阅读并点评至少一篇英文技术文章 ● Tips: 学习至少一个技术技巧 ● Sha…

C语言自定义类型 — 结构体、位段、枚举、联合

前言 本期主要对通讯录三篇博客文章进行补充 通讯录文章&#xff1a;通讯录系列文章 对结构体进行详细介绍&#xff0c;其次讲解位段、枚举、联合体 文章目录 前言一、结构体1.什么是结构体2.结构声明2.1 声明格式2.2 如何声明&#xff08;代码演示&#xff09; 3.特殊声明3.1…

蓝桥杯上岸每日N题 第七期(小猫爬山)!!!

蓝桥杯上岸每日N题 第七期(小猫爬山)&#xff01;&#xff01;&#xff01; 同步收录 &#x1f447; 蓝桥杯上岸必背&#xff01;&#xff01;&#xff01;(第四期DFS) 大家好 我是寸铁&#x1f4aa; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &a…

NetApp 入门级全闪存系统 AFF A250:小巧而强大

NetApp 入门级全闪存系统 AFF A250&#xff1a;小巧而强大 作为 AFF A 系列中的入门级全闪存系统&#xff0c;AFF A250 不但可以简化数据管理&#xff0c;还能为您的所有工作负载提供令人惊叹的强劲动力&#xff0c;价格也平易近人。 AFF A250&#xff1a;您的新 IT 专家 AFF…

提高测试用例质量的6大注意事项

在软件测试中&#xff0c;经常会遇到测试用例设计不完整&#xff0c;用例没有完全覆盖需求等问题&#xff0c;这样往往容易造成测试工作效率低下&#xff0c;不能及时发现项目问题&#xff0c;无形中增加了项目风险。 因此提高测试用例质量&#xff0c;就显得尤为重要。一般来说…

paddlenlp:社交网络中多模态虚假媒体内容核查(代码篇)

初赛之baseline解读篇 一、模型框架图1、框架解读2、评价指标解读 二、代码功能1、数据集加载2、模型定义3、模型训练4、模型预测 三、写在最后 一、模型框架图 1、框架解读 第一列是输入&#xff0c;一部分是文本&#xff08;需核查文本、文本证据材料&#xff09;&#xff…

在腾讯云服务器OpenCLoudOS系统中安装redis(有图详解)

创建安装目录&#xff1a; mkdir -p /app/soft/redis 2. 下载安装包 进入安装目录 cd /app/soft/redis/ 下载安装包 wget https://download.redis.io/releases/redis-7.0.1.tar.gz 解压&#xff1a; tar -zxvf redis-7.0.1.tar.gz 安装gcc yum install gcc-c 进入re…

C语言 函数指针详解

一、函数指针 1.1、概念 函数指针&#xff1a;首先它是一个指针&#xff0c;一个指向函数的指针&#xff0c;在内存空间中存放的是函数的地址&#xff1b; 示例&#xff1a; int Add(int x&#xff0c;int y) {return xy;} int main() {printf("%p\n",&Add);…

List集合的对象传输的两种方式

说明&#xff1a;在一些特定的情况&#xff0c;我们需要把对象中的List集合属性存入到数据库中&#xff0c;之后把该字段取出来转为List集合的对象使用&#xff08;如下图&#xff09; 自定义对象 public class User implements Serializable {/*** ID*/private Integer id;/*…