QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

Netflix 联邦 GraphQL 平台的实现过程及经验教训

  • 2021-01-20
  • 本文字数:5275 字

    阅读完需:约 17 分钟

Netflix联邦GraphQL平台的实现过程及经验教训

之前的文章QConPlus讨论中,我们讨论了 GraphQL Federation 作为一种解决方案是如何分发我们的 GraphQL 模式及其实现的。 在这篇文章中,我们会将注意力转移到成功运行联邦 GraphQL 平台所需的内容上——从它实现的过程到我们汲取的经验教训等方面。


我们迄今为止的旅程

在过去的一年中,我们已经实现了联邦 GraphQL 架构所需的核心基础架构,正如我们前一篇文章所描述的那样:

Studio Edge 架构

 

该平台上的第一个 Graph 域服务(Domain Graph Service,DGS)是我们在第一篇文章(Studio API)中讨论过的 GraphQL 单体应用。接下来,我们与其他几个应用程序团队合作一起制作了 DGS,使其 API 能与之前的单体应用一起公开。到 2019 年底,我们有了第一个使用联邦 Graph 的 Studio 应用程序,性能没有任何下降。我们知道这个架构是可行的之后,就专注于为它更广泛的使用做准备了。我们的目标是在 2020 年 4 月开放 Studio Edge 自助服务平台。

 

2020 年 4 月是一个动荡的时期,疫情大流行,人们一夜之间就过渡到了远程办公。尽管如此,各小组还是开始了成群结队地投入到 Graph 中。很快,我们每天都有数百名工程师直接为 API 贡献力量。而那个曾经是瓶颈的 Studio API 单体应用呢?我们将 Studio API 公开的字段迁移到个人拥有的 DGS 中,而不破坏用户的 API。原单体应用预计将在 2020 年底完全弃用。

 

这段旅程并非没有挑战。最大的挑战在于需在整个组织内协调这一战略。最初,有很多人持怀疑态度并有异议;这个概念相当新,需要整个组织高度一致才能成功。我们的团队花了很多时间来解决不同意见,并根据开发人员的反馈对架构进行了调整。通过我们的原型开发以及与一些关键批评声音的积极合作,我们能够逐渐增加信心并弥合关键差距。


一旦我们在这个想法上达成了广泛的一致,我们就需要确保其采用是无缝的。 这就需要构建鲁棒性强的核心基础设施,以确保良好的开发人员体验,并能解决关键的跨域问题。

核心基础设施

我们的 GraphQL 网关(GraphQL Gateway)基于 Apollo 的参考实现,并且用Kotlin编写。这使得我们能够访问 Netflix 的 Java 生态系统,同时也为我们提供了鲁棒性强的语言特性,比如用于高效并行抓取的协程(coroutines),以及具有 null 安全的表述性类型系统(expressive type system)。

 

模式注册(Schema Registry)是内部开发的,也是用的 Kotlin。为了存储模式变更,我们使用了一个内部库,该库是在Cassandra数据库之上实现的事件源模式。使用事件源允许我们实现新的开发者体验特性,比如 Schema History 视图。模式注册还集成了我们的 CI/CD 系统,如Spinnaker,可以为 DGS 自动设置云网络。

开发人员教育与经验

在之前的架构中,只有单体应用 Studio API 的团队需要学习 GraphQL。在 Studio Edge 中,每个 DGS 团队都需要在 GraphQL 上积累专业知识。GraphQL 有自己的学习曲线,对于像批处理(Batching)先行断言(Lookahead)这样的复杂情况,它会变得特别棘手。另外,正如前一篇文章所讨论的那样,理解 GraphQL Federation 和实现实体解析器(Entity Resolver)也不是一件容易的事。


我们与 Netflix 的开发者体验(Netflix’s Developer Experience,DevEx)团队合作,为开发人员提供文档、培训材料和教程。对于一般的 GraphQL 问题,我们依赖于开源社区,并建立了一个内部 GraphQL 社区来讨论诸如分页、错误处理、可空性和命名约定之类的热门话题。

DGS 框架和开发者工具

为了方便后端工程师构建 GraphQL DGS,DevEx 团队在 GraphQL Java 和 Spring Boot 的基础之上构建了一个“DGS 框架”(“DGS Framework”)。该框架解决了运行在生产环境中的 GraphQL 服务的所有跨域问题,同时也使开发人员能更容易地编写 GraphQL 解析器。此外,DevEx 还构建了强大的工具,可用于将模式推送到模式注册 Schema Registry 中,并构建了一个自助服务 UI(Self Service UI),可用于浏览各种 DGS 模式。点击查看他们的会议演讲,期待我们的同事将来能发表一篇相关的博文。DGS 框架计划于 2021 年初开源。

模式治理

Netflix 的 Studio 数据极其丰富和复杂。在早期,我们预期活动的模式管理对模式演进和整体的健康是至关重要的。我们组织中已经有一位 Studio 数据架构师(Studio Data Architect)了,他专注于跨 Studio 的数据建模和对齐。我们与他们合作,一起确定了最适用于 Studio Engineering 需求的 Graph 模式的最佳实践。

 

我们的目标是设计一个能够反映域本身而不是数据库模型的 GraphQL 模式。UI 开发人员不必构建面向前端的后端(Backends For Frontends,BFF)来根据他们的需要处理数据,相反,他们应该协助一起来塑造模式,以满足他们的需求。拥抱协作的模式设计方法对于实现这一目标至关重要。

Schema 设计工作流


协作设计过程涉及跨团队的反馈和审查。为了简化模式设计和审查,我们成立了一个模式工作组并开发了一个用于加入联邦架构的托管技术程序。虽然审查会增加产品开发过程的开销,但我们相信,优先考虑 Graph 模型的质量能减少未来的变更及其所需的反工量。审查的级别因受影响的实体而异;对于核心联邦类型,则需要更严格的审查(尽管工具有助于简化该流程)。

 

我们有一个用于改进模式的 deprecation 工作流。我们利用了 GraphQL 的deprecation特性,并且还跟踪了模式中每个字段的使用统计信息。一旦统计数据表明已弃用字段不再使用,我们就可以进行向后不兼容的变更,将该字段从模式中删除。


显示已弃用字段使用情况的客户端

 

我们采用了模式优先的方法,而不是从现有的模型中(例如 gRPC API 的 Protobuf 对象)生成模式。虽然Protobuf 和gRPC是构建服务 API 的优秀解决方案,但我们更喜欢将 GraphQL 模式与这些层解耦,以实现更清晰的 Graph 设计和独立的可扩展性。在某些场景中,我们实现了从 GraphQL 解析器到 gRPC 调用的通用映射编码,但是额外的样板对 GraphQL API 的长期灵活性来说是值得的。

 

我们使用的方法是基于“上下文高于控制”(“context over control”)的,这是Netflix文化的一个重要原则。我们没有试图严格控制整个 Graph,而是为产品团队提供指导和上下文,这样他们就可以应用自己的领域知识为自己的领域创建灵活的 API。随着该架构的成熟,我们将继续监控模式运行情况,并在需要的时候开发新的工具、流程和最佳实践。

可观测性

在我们之前的架构中,可观测性是通过人工分析和 API 团队的路由来实现的,它的可伸缩性很差。对于我们的联邦架构,我们以一种更具可伸缩性的方式来优先解决可观测性的需求。


我们优先考虑如下三个方面:

  • 报警——当发生错误时(when)报告

  • 发现——轻松确定哪些(what)是不工作的

  • 诊断——调试某些东西不工作的原因(why)

 

我们在这一领域的指导度量指标是平均修复时间(MTTR)以及服务等级目标和服务等级指标(SLO/SLI)。

 

我们与 Netflix 遥测团队的专家合作。我们将网关和 DGS 架构组件与Zipkin、内部分布式跟踪工具Edgar和应用程序监控工具TellTale 集成在一起。在 GraphQL 中,几乎每个响应都是 200,错误块中包含了自定义的错误。我们从响应中检查这些自定义的错误代码,并将它们发送到我们的度量服务Atlas中。这些集成为 GraphQL API 的使用者和开发人员奠定了丰富的可见性和洞察力的良好基础。

 

监控联邦请求生命周期的 Edgar Trace

 

联邦请求的时间轴视图


分布式日志关联(Distributed Log Correlation)有助于调试更复杂的服务问题。通过显示处理请求所涉及的所有系统的应用级日志详细信息,我们可以更深入地了解堆栈中发生的事情。开发人员可以很容易地看到与给定请求同时发生的事情,以排查可能影响交互的周边因素。

一个跨多个服务记录的联邦请求的日志

 

为了解决“我应该问谁(who)……”的路由问题,我们集成了从 GraphQL 类型和字段到它们所属团队的支持(support)渠道的深度链接。现在,寻找 support 只需单击跟踪中的链接,这有助于缩短 MTTR 并能减少网关团队所需的参与次数。

保护联邦 Graph 的安全

 我们的目标是在整个联邦架构中实现可靠且一致的安全实践。为了实现这一点,我们与 Netflix 的安全专家合作,将安全性构建到 Graph 中。让我们来看下我们安全解决方案的两个基本部分:AuthN 和 AuthZ。

身份认证

我们在 Studio 空间中的所有产品体验都需要一个经过认证的帐户,因此我们将 GraphQL 网关的访问权限限制为只允许受信任的经过身份验证的调用者。此外,Graph Introspection仅限于 Netflix 的内部开发人员。

授权

在 Studio Edge 之前,授权逻辑在各个团队之间是分散的。一些团队在他们的 BFF 中实现了授权,一些在微服务中实现了授权,而另一些团队则在这两处兼而有之。结果往往是,由于用户访问的 UI 不同,对于给定的数据,授权也不同。UI 团队还发现他们需要对每个新的前端实现(以及重新实现)进行授权检查。


在 Studio Edge 中,我们将授权责任委托给 DGS 的所有者。这就实现了在不同应用程序中对同一用户进行一致的授权。此外,产品经理、工程师和安全团队可以很容易地了解谁可以访问哪种数据类型以及如何访问。


我们在 Netflix 内部提供了多种授权服务:从基于用户身份授予访问权限的简单系统,到引入角色和功能概念的更细粒度的系统。DGS 开发人员可以根据自己的需要选择解决方案。然后,他们只需使用 @Secured 注解对解析器进行注解,并将其配置为使用一个可用的系统即可。如果需要,可以在解析器或下游系统中实现更复杂的授权。

授权的未来

我们目前正在构建一个支持 GraphQL 授权解决方案的原型。注册模式时,Schema Registry 会自动为每个字段及其相应类型生成访问控制组(Access Control Groups,ACGs)。产品经理和 DGS 工程师可以决策这些生成的 ACG 的成员资格和规则。由于 ACG 映射到 GraphQL 中的某个字段,因此 DGS 框架会在执行期间自动应用与 ACG 关联的规则。

面向失败的架构设计

GraphQL 网关是所有请求的单一入口点;网关上的故障可能会导致严重的中断。根据 Netflix 工程的最佳实践,我们假设会发生故障,并设计方法来减轻这些故障的影响。以下是我们用来确保网关层具有弹性的设计原则:

  1. 单一用途

  2. 无状态服务

  3. 需求控制

  4. 多区域

  5. 按功能分片

 

首先,我们将网关层的职责集中在一个用途上:解析客户端查询,然后构建和执行查询计划。通过缩小范围,我们限制了可能发生的问题的范围。我们的目标是即时执行日志记录和度量指标之外的任何其他资源密集型操作。在网关层中添加其他不相关的逻辑可能会增加在这一关键层中出现故障的表面积。

 

其次,我们运行网关服务的多个无状态实例。任何网关实例都能够为任何请求生成和执行查询计划。当我们对网关层进行代码变更时,我们会在正式投入生产之前对它们进行严格的测试。

 

第三,我们通过应用需求控制来平衡每个请求消耗的资源。我们限制调用方的速率,以避免底层数据库过载,这些数据库是大多数领域元素的来源。我们还对所有传入的查询运行静态查询开销计算,并拒绝昂贵的查询,以避免网关和 DGS 资源的阻塞。我们的合作伙伴了解这些折衷方案,并与我们一起来满足这些要求,重新处理昂贵的查询并减少大的调用。

 

第四,我们在世界各地的多个 AWS 区域中部署了网关层。这使我们能够限制爆炸半径以应对发生不可避免的问题。当问题发生时,我们可以将故障转移到另一个区域,以确保我们的客户受到的影响最小。

 

最后,我们部署多个网关层的功能分片(Shard),每个分片中的代码均相同,传入的请求根据类别进行路由。例如,GraphQL 订阅(Subscription)通常会导致长时间的连接,而查询(Query)和突变(Mutation)则是短暂的。我们使用一个单独的实例组来处理订阅,因此“连接耗尽”也不会影响查询和突变的可用性。

 

我们还可以做更多的事情来提高弹性。我们计划对网关部署以及最终的模式变更进行金丝雀(Canary)部署和分析。今天,我们的网关通过轮询模式注册来动态更新其模式。我们正在通过将联邦配置存储在一个版本化的 S3 存储桶中来实现这些功能的解耦,从而使网关能够抵御模式注册的故障。

结束语

GraphQL 和 Federation 已成为 Studio 应用程序的效率倍增器。基于此,我们最近使用 GraphQL Federation 为 iOS 和 Android 上的 Netflix 消费者应用程序搜索页面创建了原型。为了做到这一点,我们创建了三个 DGS 来为消费者 Graph 的最小部分提供数据。我们正在将一小部分用户切流到这个替代技术栈中,并测量其高层度量指标。我们很高兴看到结果,并进一步探讨其在 Netflix 消费者领域的适用空间。


尽管我们拥有积极的经验,但 GraphQL Federation 尚处于成熟期的早期,可能对每个团队和组织来说并不都是最合适的。学习 GraphQL 和 DGS 开发、运行联邦层并进行迁移需要合作团队的高度投入以及无缝的跨功能协作。如果你正在考虑朝这个方向发展,我们建议你查看 Apollo 为Federation提供的SaaS产品,以及许多学习 GraphQL 相关的在线资源。对于像我们这样拥有大量的微服务并需要其聚合在一起的生态系统来说,开发速度和可操作性的提高使得这种转变是值得的。


最后,我们想听听你的意见!如果你已经实现了 Federation,或者尝试用另一种方法来解决这个问题,我们很乐意向你了解更多信息。分享知识是我们这个行业快速学习和提高的方式之一。最后,如果你想参与解决诸如 Netflix 弹性相关的复杂而有趣的问题,请查看我们的招聘页面或直接联系我们。

 

英文原文链接:


https://netflixtechblog.com/how-netflix-scales-its-api-with-graphql-federation-part-2-bbe71aaec44a

2021-01-20 16:472400

评论

发布
暂无评论
发现更多内容

每个开发人员都应该知道的 10 个 GitHub 仓库

LeanCloud

GitHub web开发

推荐计划 | 推荐好友用 CODING,获高额返现奖励

CODING DevOps

团队管理 敏捷开发 研发工具 开发团队

飞猪基于 Serverless 的云+端实践与思考

阿里巴巴云原生

Serverless 容器 运维 云原生 监控

程序员写好技术文章的几点小技巧

阿里巴巴云原生

程序员 云原生 写作 写作技巧

Kubernetes 普及系列:容器基础入门

CODING DevOps

Kubernetes

仰望天空,脚踏实地 —— CODING OKR 全新上线

CODING DevOps

团队管理 OKR

字节跳动Java岗一二三面全经过分享

北游学Java

Java 字节跳动 面试

简单了解 MySQL 中相关的锁

leonsh

MySQL 后端

ETL-KETTLE工具使用

this

Java 数据 数据同步 ETL

玩转直播系列之消息模块演进(3)

vivo互联网技术

Java 服务器 消息系统 直播技术

记十亿级Es数据迁移mongodb成本节省及性能优化实践

杨亚洲(专注MongoDB及高性能中间件)

MySQL 数据库 mongodb 架构 分布式数据库mongodb

2021 DevOpsDays 东京站完美收官 | CODING 专家受邀分享最新技术资讯

CODING DevOps

DevOps CI/CD

Spark知识点简单总结

五分钟学大数据

大数据 spark 5月日更

我粉了!阿里大牛从内部带出来的百亿级高并发系统,从基础到实战、面面俱到

Java 程序员 架构 面试

首届HarmonyOS开发者创新大赛颁奖典礼于深圳召开

科技汇

高级软件工程师必备的五大技能

架构精进之路

5月日更

部署混合云环境的5大挑战

云计算

☕【JVM 技术之旅】让你完全攻克内存溢出(OOM)这一难题(上)

洛神灬殇

JVM OOM 异常 Exception 5月日更

「DataPipeline」完成数千万B轮融资,加速构建中国的世界级数据中间件产品

DataPipeline数见科技

融资

并发王者课 - 青铜 3: 双刃剑-理解多线程带来的安全问题

MetaThoughts

Java 多线程 并发 王者并发课

iOS面试--拼多多最新iOS开发面试题

一意孤行的程序员

ios swift 面试 ios开发 知识分享

华为HMS生态和1+8+N的交叉点,点透棋局的华为帐号

脑极体

MindSpore:不用摘口罩也知道你是谁

华为云开发者联盟

算法 人脸识别 口罩 mindspore 口罩人脸

阿里P9架构师强烈推荐:想拿60W以上年薪必看,Java高并发四套小册。

Java架构追梦

Java 阿里巴巴 架构 面试 高并发

百度 Serverless 架构揭秘与应用实践

百度开发者中心

百度 开源 Serverless 云原生

超级详细!全网独家首发的SpringCloud Alibaba 到底有多强?

Java 程序员 架构 面试

Hive窗口函数与分析函数

大数据技术指南

hive 5月日更

阿里云原生开源大家族加入中科院软件所开源软件供应链点亮计 - 暑期 2021

阿里巴巴云原生

开源 容器 微服务 开发者 云原生

参与 Apache 顶级开源项目的 N 种方式,Apache Dubbo Samples SIG 成立!

阿里巴巴云原生

开源 开发者 云原生 dubbo 中间件

Nginx的11个执行阶段详解

运维研习社

nginx 运维 源码剖析 5月日更

做一次黑客,入侵一次服务器

叫我阿柒啊

Docker 入侵 docker远程 redis注入

Netflix联邦GraphQL平台的实现过程及经验教训_架构_Netflix技术博客_InfoQ精选文章