Netflix 开源用于 Spring Boot的 GraphQL 服务框架DGS

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Netflix 公司着力开发的 Domain Graph Service(DGS)框架现已正式成为开源项目。DGS 框架简化了针对独立与联合 GraphQL 服务的 GraphQL 实现。而在高强度的现实锤炼之后,这套框架也变得愈发稳定强健。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过将项目开源,我们希望为 Java 及 GraphQL 社区做出贡献,同时与各位使用框架、增强框架的参与者们携手合作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DGS 框架的主要功能包括:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基于注释的 Spring Boot 编程模型"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用于将查询测试编写为单元测试的测试框架"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Gradle 代码生成插件,可通过 GraphQLschema 创建 Java\/Kotlin 类型"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与 GraphQLFederation 轻松集成"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与 Spring Security 相集成"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GraphQL 订阅 (WebSockets 与 SSE)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"文件上传"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"错误处理"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自动支持 interface\/union 类型"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供面向 Java 的 GraphQL 客户端"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可插拔 Instrumentation"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"我们为何需要 DGS 框架"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2019 年春季,Netflix 公司开启了这段伟大的联合 GraphQL 架构探索之旅。向这种新型联合架构的过渡,意味着我们的众多后端团队需要在 Java 生态系统中使用 GraphQL。之前我们曾发表博文,提到 Netflix 已经在 Spring Boot 上实现了后端开发标准化。因此,要让这套联合架构取得成功,我们需要在 Spring Boot 中为 GraphQL 提供良好的开发者体验。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为此,我们在 Spring Boot 上创建起自有框架,其中用到 graphql-java 库。这套框架最初只供内部使用,主要强调与 Netflix 生态系统相集成以实现跟踪、日志记录及指标整理等。但在此期间,我们也一直强调应该将框架进行适当模块化。很明显,我们构建的大多数框架并不特定于 Netflix,主要用于提供一种更简便的 GraphQL 服务(独立与联合)构建方法。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Schema 优行开发"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Schema 代表的是 GraphQLAPI。正是 schema 的存在,让 GraphQL 如何强大、又与 REST 有所不同。GraphQL 模式会根据查询及变异操作,配合相关类型与字段以描述 API。API 用户可以精确指定希望在查询中检索的字段,借此极大提高 GraphQLAPI 的灵活性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GraphQL 分为两种不同方法:schema 优先与代码优先。通过选择 schema 优先开发方法,您可以使用 GraphQLSchema 语言手动定义 API 的 schema。服务中的代码将仅用于实现此 schema。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用代码优先开发,您无需使用任何 schema 文件。相反,由运行时根据代码中的定义生成 schema。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们的框架同时支持 schema 优先与代码优先这两种方法。在 Netflix,我们明确倾向使用 schema 优化的开发方式,理由包括:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"Schema 设计是开发者体验中的重中之重。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"能够为工具提供一种更简便的 schema 使用方法。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"由 schema 差异能够让变更引发的向下不兼容性更明显。在联合 GraphQL 架构下,向下兼容性无疑至关重要。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"尽管使用代码生成 schema 一般更有速度优势,但我们愿意投入更多时间来建立起易于理解的 schema 协作模式设计,希望借此建立更出色的 API。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"框架实操"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此框架的核心围绕 Spring Boot 开发者所熟悉的、基于注释的编程模型进行。项目网站上提供全面的说明文档,下面我们将通过一项示例,向大家展示如何轻松使用这套框架。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"让我们先从简单的 schema 开始。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/28\/289fbe13982088c2e5f425839c518c34.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要实现此 API,我们需要编写一个数据提取程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/12\/12fc0381a12b8540699bc9116164733a.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中的 Show 类型是一个简单 POJO,通常由 Gradle 的 DGS 代码生成插件所生成。使用 @DgsData 注释方法,即可为字段实现数据获取程序。请注意,我们不需要为每个字段获取数据;这里可以直接返回 Java 对象,由框架完成其余工作。这套框架还具有多种其他便捷性优势,例如本示例中使用的 @InputArgument 注释。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此代码足以让 GraphQL 端点保持运行。接下来,只需要启动 Spring Boot 应用程序,即可使用 \/graphql 端点以及 \/graphiql 上开箱即用的 GraphiQL 查询编辑器。示例中的代码简单明了,而且即使是使用联合类型,使用 @Secured 或者使用扩展点添加指标与跟踪,代码内容也不会有太大区别。总之,框架本身将负责解决所有繁重的工作内容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本框架的另一大关键,在于支持轻量级查询测试。通过测试流程,您无需使用 HTTP 端点即可执行查询。测试本身的使用感受与普通 Junit 测试基本一致。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/28\/284e0e26413006fad12f6aa567f33511.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"关于这套框架的完整说明文档,请参见 DGS框架"},{"type":"link","attrs":{"href":"https:\/\/netflix.github.io\/dgs\/","title":"xxx","type":null},"content":[{"type":"text","text":" GitHub repo。"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"对接 GraphQL 服务器生态系统"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那么,DGS 框架要如何全面适应现有 GraphQL 生态系统?当前生态系统涵盖服务器、客户端、联合网关以及工具,可帮助您进行查询测试、schema 管理、代码生成等。在使用 JVM 构建 GraphQL 服务器时,生态系统也为我们提供大量 schema 优先库与代码优先库选项。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"graphql-kotlin 是一套面向 Kotlin 语言的高人气代码优先库。graphql-java 则是在 Java 当中实现 schema 优先 GraphQLAPI 的首选方案,但在设计上属于低级库。graphql-java-kickstart 入门程序由一组用于实现 GraphQL 服务的库组成,并在 graphql-java 的基础之上提供 graphql-java-tools 与 graphql-java-servlet。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"无论您使用 Java 还是 Kotlin,我们的框架都能提供在 Spring Boot 中构建 GraphQL 服务的简便方法。此框架还可分别用于构建独立服务与联合 GraphQL。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"联合"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DGS 框架能够以便捷的方法实现联合 GraphQL 服务。联合机制,意味着各服务能够共享网关所公开的统一图。通常,服务使用由 Apollo 联合规范所定义的 @extends 指令,借此在统一 schema 中实现服务共享与类型扩展。这也是一种将大规模单体 GraphQLschema 拆分成多个微服务的有效方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于传入的查询,联合网关能够构建查询计划以调用所需的服务,借此完成查询操作。每项服务又需要能够响应 _entities 查询,以便在一定程度上完成对所拥有数据的查询。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面以 Reviews(评论)服务为例,了解如何在 reviews 字段扩展之前定义的 Show 类型:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/14\/14ad331b79068e30c919a6f9db4d9408.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/04\/04c3c005d064a727b16173a452bbeea1.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"带有 Shows 与 Reviews DGS 的联合 GraphQL 架构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在此 schema 下,Reviews DGS 需要为联合 Show 类型实现一个解析器,并在其中填充 reviews 字段。大家可以使用 @DgsEntityFetcher 注释轻松完成此项操作,如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/90\/90b2863605c6d46c5414cf7a43f11063.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此框架还使您可以轻松通过代码生成功能对联合查询加以测试,借此为基于 schema 的服务生成 _entities 查询。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"框架架构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从开发之初,我们就专注于实现代码模块化。这是一项重要的设计选择,能够在不影响我们内部团队的前提下开源大部分框架。但我们无法使用 Java 9 中引入了模块系统,因为 Netflix 内部的多数应用程序仍在使用 java 8。但借助 Gradleapi 与 implementation 模块,我们得以创建起简单整洁的模块结构。在 Netflix,我们将大量 Spring Boot 扩展与自有基础设施集成起来。我们将这套体系称为 Spring Boot Netflix。DGS 框架基于标准的开源 Spring Boot 构建而成。最重要的是,我们也有部分模块与特定基础设施相集成,且仅使用核心框架提供的扩展点。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下图所示,为各模块如何实现装配集成:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/3d\/3d64ee9475a1ecbe2642746fa9832759.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"包含 Netflix 与 OSS 模块的 DGS 框架"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"分布式跟踪与指标"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Netflix,我们拥有一夶包含跟踪、指标、分布式日志记录以及身份验证 \/ 授权等功能的自定义基础设施。如前所述,DGS 框架能够与这套基础设施集成起来,提供开箱即用的无缝化体验。虽然这些功能并未开源,但仍可以轻松被添加到框架当中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"该框架还支持 graphql-java 库中定义的 Instrumentation 类。通过实现 Instrumentation 接口并通过 @Component 进行注释,此框架可以自动拾取这些类。感兴趣的朋友可以参阅说明文档中的相关"},{"type":"link","attrs":{"href":"https:\/\/netflix.github.io\/dgs\/advanced\/instrumentation\/","title":"xxx","type":null},"content":[{"type":"text","text":"参考示例"}]},{"type":"text","text":"。我们也期待更多社区参与者围绕分布式跟踪与指标的通用模式做出贡献。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"立即体验"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要开始使用 DGS 框架,请参阅说明文档及教程。要为 DGS 框架做出贡献,请在 GitHub 上查看 DGS 框架项目。我们还拥有一款 Gradle代码生成插件,用于根据 GraphQLschema 生成 Java 与 Kotlin 类型。要参与代码生成插件的贡献,请在 GitHub 上查看此项目。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"团队成果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DGS 框架在 Netflix 中获得的成功,离不开各参与团队的共同努力。我们要感谢来自 BFG 团队的各位同事,他们与我们共同完成了这段奇妙的探索之旅。最后,我们还要感谢各位用户给出的及时反馈与代码贡献。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文链接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/netflixtechblog.com\/open-sourcing-the-netflix-domain-graph-service-framework-graphql-for-spring-boot-92b9dcecda18?gi=978ff7b803d3","title":"","type":null},"content":[{"type":"text","text":"https:\/\/netflixtechblog.com\/open-sourcing-the-netflix-domain-graph-service-framework-graphql-for-spring-boot-92b9dcecda18?gi=978ff7b803d3"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章