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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章