我们如何使用GraphQL构建Globoplay的API网关

我知道您每天都不会听到此消息,但是我从未在一个项目中工作过,在该项目中,我会选择GraphQL而不是经典的Rest API来抽象客户端/服务器通信。 我的意思是,通常不会听到这样的消息,因为当今互联网上有大量写得很好的文章,它们描述了当使用GraphQL解决任何类型的问题时有多么神奇。
此外,还有另一件事使该短语变得不常见:在生产中使用GraphQL的精美项目的外观如何。
来吧,他们看起来很花哨。

老实说,我一直怀疑这不是现实世界。 就像,当您每天有成千上万甚至数百万的用户打开您的产品时,似乎无法在生产中使用,就像我们的情况一样,认为您不能再依赖旧的了就感到非常不舒服按资源http缓存进行时尚处理

是的,确实感觉不舒服。 首先,实际上。
但是,当我们开始理解我们需要对体系结构进行的更改时
(也是我们的想法!)拥抱它们 ,以便交付利益相关者期望看到的产品,事情开始变得更加简单和舒适。

但是,在我们继续之前,我相信某些环境可以帮助您了解我们的产品在哪里以及我们如何改变了主意。


Globoplay是由Grupo Globo创建和开发的视频流平台,Grupo Globo是巴西和拉丁美洲最大的媒体和传播集团。

它是称为OTT的产品之一。 它目前仅在巴西受支持,其内容始于TV Globo(免费电视)的内容,允许用户观看刚刚由TV Globo广播的节目(称为追赶)。 随着时间的流逝,我们开始通过WebTV,iOSandroid客户提供独家的国家内容以及国际系列/电影。

够了,兄弟…


在2018年中期,我们有两个后端(BFF)执行非常相似的任务:一个用于Web,另一个用于iOS,Android和TV。 尽管他们仅应根据每个客户的特点来区分,但我们最终在下面重复了很多服务,其中最重要的是: 努力

尽管我非常喜欢“后端到前端”的想法( 听起来很酷 ),但我们无法保留当前的体系结构。 不仅是因为我刚才说的原因,还因为每个BFF为其客户提供的内容稍有不同,而业务团队开始要求一些新的东西: 所有客户中的普遍存在

就是这个! 我们需要统一我们重复的基础设施,为具有不同需求的不同客户提供支持,从而为用户提供无处不在的体验。


现在您可能想知道为什么您重复了下面的内容?
好吧,是的……这是没有意义的,答案可能像荷马·辛普森的回答一样简单: 就像我到这里时那样。

开玩笑。 尽管这是事实,但它并不能真正回答问题。 我们之所以重复下面的内容,是因为这些团队没有一起工作。 他们是具有不同流程和目标的不同团队。 仅仅过了一段时间,我们才意识到他们应该一起工作,并且当我们将它们合并为一个团队时,我们开始看到这样做的好处。

我记得有一天我花了几个小时盯着窗户想着我们所有的功能要求。 没人感到惊讶的是,我对我们需要支持的所有内容进行的审查越多,GraphQL就越有意义。

我的意思是,它可以像手套一样满足我们的一些要求:

  • 电视需要大型节目海报,而手机则需要小型节目海报。

一旦POC开始,我们就对最常用的GraphQL实现进行了一些研究,我们发现Apollo GraphQL在最佳结果中。

如果您愿意从GraphQL开始,但是从未读过有关Apollo的文章,我强烈建议您查看他们的文档。

Apollo GraphQL是GraphQL实现,可帮助开发团队从多个服务(包括REST API和数据库)传递数据。 它还包括用于客户端和服务器的两个开源库,开发人员工具,分析,教程等。 在阅读他们的文档一段时间后,我们决定将Apollo Server作为Jarvis的核心。

正如我之前所说,我知道周围有很多很棒的GraphQL教程,也许我不需要创建另一个。 但是,我将描述在POC期间测试的一些功能,这些功能帮助我们创建了Jarvis生产就绪版本,例如: 数据源,查询成本验证,应用程序/ http缓存

Apollo Server是一个围绕nodejs服务器的简单GraphQL实现包装器。 启动服务器的时间不超过5分钟:

如您在解析器中所见, program根查询始终返回空响应。 为了使其返回一些数据,我们需要为Data Source添加支持

Apollo数据源是一些类,它们封装了从给定服务中获取数据的功能 ,并内置了对缓存重复数据删除错误处理的支持 。 太酷了,我们只需要担心编写与后端交互特定代码,其余的工作由Apollo Server负责。 作为此示例的一部分,我们实现了一个REST数据源,该数据源负责从称为程序的API中获取数据。

为了使其工作,我们需要调整服务器文件以使用刚刚创建的数据源:

太好了! 通过几行代码,我们才开始通过GraphQL API从另一个来源提供数据。 现在,您应该可以打开Playground并运行一些查询。


随着我们GraphQL模式的发展,更多的客户端开始从中查询数据,我们需要考虑防止客户端创建昂贵的查询,这些查询可能会使我们的服务器花费太多时间来回答问题,从而最终影响其负载和性能。

关于如何保护GraphQL API免受恶意查询,有一些不错的文章。 我强烈建议您开始阅读本指南,并实施一个简单的复杂性成本验证规则 ,以了解这些类型的验证是如何工作的。

在继续进行并花费大量时间实施查询成本分析之前,请了解您的架构并确定您需要这种安全性。


到目前为止,我们已经准备好了几乎可以投入生产的GraphQL API的最低工作版本。 在这样做之前,我们需要考虑可以使我们的服务在生产中保持稳定的功能,无论所连接客户端上的最终峰值如何。

快来救援吧!

我认为,在这种情况下,缓存策略是一个很大的因素,必须根据API在生产中所面临的场景进行计划。 您可以决定在应用程序级别 (内存中或Redis) ,http级别 (CDN,负载均衡器)或同时缓存查询结果!

同样,这确实取决于您的情况。

关于应用程序级别的缓存,我的建议是从简单的分布式内存中缓存(Apollo Data Sources默认支持)开始,然后仅在需要时才移动到远程Redis实例。

在http级缓存中,建议您阅读类似的文章,其中涉及自动持久查询CDN缓存
这个想法是你可以添加
将指令伪指令缓存到架构中,以定义每种类型或字段的最长期限。 执行查询后,会将cache-control标头添加到服务器响应中(遵循查询中所请求的字段中定义的最低max-age) 。 然后,服务器和客户端之间的任何层都可以使用标头中的值来缓存结果。 您还可以为整个架构定义默认的最长期限:


在Jarvis POC中完成这些步骤后,我们将集中精力评估将在生产中使用的监视工具-但是我将在下一篇文章中解释这一部分。

扰流板警报:Apollo Engine很棒…

可以想象,Jarvis在生产中做得很好。
我们能够解决我们在设计体系结构时发现的大多数问题,包括性能,缓存和开发经验。

当然,我们花了一些时间来了解我们对团队用于读取/写入数据的方式所做的所有更改。 而且我认为有必要提供这些要求。

现在,团队正在享受与该API网关一起使用的事实,该API网关使他们能够要求完成工作所需的一切。
业务团队很兴奋,因为我们为他们所要求的所有客户提供了普遍支持。
我的老板很高兴,因为它奏效了! –
那很重要!


顺便说一句,完整的GraphQL API教程可以在GitHub上找到 享受❤️!