自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

API開發(fā),gRPC還是GraphQL?

譯文 精選
開發(fā) 架構(gòu)
GraphQL既是一種用于API的查詢語言,且GraphQL對API中的數(shù)據(jù)提供了一套易于理解的完整描述,使得客戶端能夠準(zhǔn)確地獲得它需要的數(shù)據(jù),而且沒有任何冗余,也讓API更容易地隨著時(shí)間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開發(fā)者工具。

?譯者 | 崔皓

審校 | 云昭

gRPC是由Google開發(fā)的一個(gè)高性能、通用的開源RPC框架,主要面向移動(dòng)應(yīng)用開發(fā)且基于HTTP/2協(xié)議標(biāo)準(zhǔn)而設(shè)計(jì),同時(shí)支持大多數(shù)流行的編程語言。

GraphQL既是一種用于API的查詢語言,且GraphQL對API中的數(shù)據(jù)提供了一套易于理解的完整描述,使得客戶端能夠準(zhǔn)確地獲得它需要的數(shù)據(jù),而且沒有任何冗余,也讓API更容易地隨著時(shí)間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開發(fā)者工具。

兩者看起來并用途不相同,但其實(shí)在通信場景中很多開發(fā)者面臨如何選擇的問題。本文筆者帶領(lǐng)大家從實(shí)用的角度去一一剖析gRPC與GraphQL的取舍之道!

一、開篇

本文主要介紹使用gRPC和GraphQL的時(shí)機(jī),先說結(jié)論:推薦大家在客戶端與服務(wù)器之間的通信場景中使用GraphQL,在服務(wù)器與服務(wù)器之間的通信場景使用gRPC。此外,文末會介紹關(guān)于例外情況的處理方式。

二、背景介紹

gRPC是由谷歌在2016年發(fā)布的,它是一種高效且對開發(fā)者友好的服務(wù)器間通信協(xié)議。GraphQL是由Meta公司在2015年發(fā)布的,是一種高效的、對開發(fā)者友好的客戶端-服務(wù)器通信協(xié)議。兩者都比REST有明顯的優(yōu)勢,并且有很多共同點(diǎn)。

我們將在文章中花大量的篇幅比較它們的特點(diǎn),然后總結(jié)每個(gè)協(xié)議的優(yōu)點(diǎn)和缺點(diǎn)。最后,我們會描述每種協(xié)議都適合哪些特定的領(lǐng)域,以及什么時(shí)候會出現(xiàn)跨領(lǐng)域使用不同協(xié)議。

三、比較gRPC和GraphQL的功能

1.界面設(shè)計(jì)

gRPC和GraphQL都是界面描述語言(IDL),描述了兩臺計(jì)算機(jī)如何進(jìn)行通信。它們適用于不同的編程語言,我們可以使用codegen工具來生成多種語言的類型化接口。IDL抽象出了傳輸層;GraphQL與傳輸無關(guān),但通常工作在HTTP之上,而gRPC則工作在HTTP/2之上。我們不需要知道傳輸層的細(xì)節(jié),比如REST中的方法、路徑、查詢參數(shù)和正文格式。我們只需要知道針對一個(gè)獨(dú)立的節(jié)點(diǎn),如何使用高級客戶端庫與之通信。

2.信息格式

gRPC使用協(xié)議緩沖區(qū)(又稱protobufs),這是一種二進(jìn)制格式,只包括數(shù)值(傳遞的內(nèi)容),而GraphQL使用JSON,它是基于文本的,除了數(shù)值外還包括字段名(數(shù)值的含義)。二進(jìn)制格式與較少的信息發(fā)送相結(jié)合,通常導(dǎo)致gRPC消息比GraphQL消息小。(雖然高效的二進(jìn)制格式在GraphQL中是可行的,但它很少被使用,也不被大多數(shù)的庫和工具所支持)。

影響消息大小的另一個(gè)方面是overfetching(過度獲取):我們決定是否只請求特定的字段或總是接收所有的字段(通過避免"overfetching"過濾掉我們不需要的字段,只接受我們需要的字段)。因此,對于GraphQL而言利用了overfetching技術(shù)可以在請求中指定需要哪些字段,而在gRPC中,我們可以使用FieldMasks作為請求的可重用的過濾器,該過濾器和overfetching有異曲同工之妙。

gRPC使用二進(jìn)制格式的另一個(gè)好處是,比GraphQL信息的序列化和解析更快。當(dāng)然,缺點(diǎn)也很明顯,它比JSON而言更難查看和調(diào)試,畢竟JSON的信息結(jié)構(gòu)更加適合人類閱讀。在Temporal項(xiàng)目中(開源微服務(wù)平臺),我們默認(rèn)使用protobuf的JSON格式,以利于開發(fā)者體驗(yàn)的可見性。(這失去了二進(jìn)制格式帶來的效率,但更看重效率的用戶可以切換到二進(jìn)制)。

3.默認(rèn)值

gRPC不在消息中包括默認(rèn)值,而GraphQL可以對參數(shù)進(jìn)行默認(rèn)值的設(shè)置,但不能對請求字段或響應(yīng)類型進(jìn)行默認(rèn)值設(shè)置。這導(dǎo)致gRPC消息尺寸較小的另一個(gè)因素。它還影響了消費(fèi)gRPCAPI的DX,在不設(shè)置輸入字段和將該字段設(shè)置為默認(rèn)值沒有什么區(qū)別,默認(rèn)值也是基于字段類型的值。我們不能把`behavior`枚舉輸入字段默認(rèn)為`BEHAVIOR_FOO=2`--我們必須把默認(rèn)值放在第一位(`BEHAVIOR_FOO=0`),這意味著它在總是默認(rèn)值,或者我們遵循推薦的做法,定義一個(gè)`BEHAVIOR_UNSPECIFIED=0`枚舉值。

enumBehavior{
behavior_unspecified=0。
behavior_foo=1;
behavior_bar=2;
}

API提供者需要傳達(dá)UNSPECIFIED的意思(通過記錄"unspecified將使用默認(rèn)行為,目前是FOO"),消費(fèi)者需要考慮服務(wù)器的默認(rèn)行為在未來是否會改變(如果服務(wù)器在消費(fèi)者正在創(chuàng)建的業(yè)務(wù)實(shí)體中保存了UNSPECIFIED/0值,而服務(wù)器后來改變了默認(rèn)行為,那么該實(shí)體將會有所不同),以及這種改變是否是所期望的。如果并不希望如此,客戶需要將該值設(shè)置為當(dāng)前的默認(rèn)值。

這種方式比gRPC版本更簡單,這種方式可以知道如果不提供字段會發(fā)生什么,而且我們不需要考慮是否要自己傳遞默認(rèn)值。

其他類型的默認(rèn)值也有一些特殊情況。對于數(shù)字而言,有時(shí)默認(rèn)的0是一個(gè)有效的值,而有時(shí)它將意味著一個(gè)不同的默認(rèn)值。對于布爾型,默認(rèn)的false會導(dǎo)致字段被負(fù)數(shù)命名。當(dāng)我們在編碼時(shí)給布爾變量命名時(shí),我們使用正向命名。例如,我們通常會聲明letretryable=true而不是letnnotallow=false。人們通常認(rèn)為前者更易讀,因?yàn)楹笳咝枰~外的步驟來理解雙重否定("notRetryable是假的,所以它是可重試的")。但是如果我們有一個(gè)gRPCAPI,我們希望默認(rèn)狀態(tài)是可重試,那么我們就必須把這個(gè)字段命名為nonRetryable,因?yàn)榭芍卦囎侄蔚哪J(rèn)值是false,就像gRPC中的所有布爾值一樣。

4.請求格式?

在gRPC中,我們一次調(diào)用一個(gè)方法。如果我們需要的數(shù)據(jù)比一個(gè)方法所返回的要多,就需要調(diào)用多個(gè)方法。如果我們需要第一個(gè)方法的響應(yīng)數(shù)據(jù),以便知道下一步調(diào)用哪個(gè)方法,那么我們就會連續(xù)進(jìn)行多次往返。除非我們和服務(wù)器在同一個(gè)數(shù)據(jù)中心,否則會造成很大的延遲。這個(gè)問題被稱為underfetching,指請求的返回的數(shù)據(jù)信息不夠,這樣導(dǎo)致我們需要發(fā)多個(gè)請求去獲取數(shù)據(jù)。

這也是GraphQL設(shè)計(jì)能夠解決的問題之一。在高延遲的移動(dòng)連接中,能夠在一次請求中獲得需要的所有數(shù)據(jù),這一點(diǎn)特別重要。在GraphQL中,我們在請求中發(fā)送一個(gè)字符串,其中包括我們想要調(diào)用的所有方法(稱為queries和mutations)以及基于第一層結(jié)果的嵌套數(shù)據(jù)。嵌套的數(shù)據(jù)可能需要從服務(wù)器到數(shù)據(jù)庫的后續(xù)請求,但它們通常位于同一個(gè)數(shù)據(jù)中心,應(yīng)該有亞毫秒級別的網(wǎng)絡(luò)延遲。

GraphQL的請求靈活性讓前端和后端團(tuán)隊(duì)的耦合度降低。前端開發(fā)者不需要等待后端開發(fā)者在方法的響應(yīng)中添加更多的數(shù)據(jù)(這樣客戶端就可以在單個(gè)請求中接收數(shù)據(jù)),而是可以在請求中添加更多的查詢或嵌套結(jié)果字段。當(dāng)有一個(gè)涵蓋整個(gè)數(shù)據(jù)的GraphQLAPI時(shí),后端發(fā)生變化而導(dǎo)致前端團(tuán)隊(duì)時(shí)受阻的情況就會明顯減少。

GraphQL請求指定了所有需要的數(shù)據(jù)字段,這意味著客戶端可以使用聲明式數(shù)據(jù)獲?。╠eclarativedatafetching):生命視圖組件接下來所需要的數(shù)據(jù),而不是強(qiáng)制性地獲取數(shù)據(jù)(比如調(diào)用`grpcClient.callMethod()'),GraphQL客戶端庫將這些合并成一個(gè)請求并提供數(shù)據(jù),在數(shù)據(jù)變化時(shí)也可以提供數(shù)據(jù)。在Web開發(fā)中使用React而不是jQuery:聲明組件應(yīng)該是什么樣子,并在數(shù)據(jù)變化時(shí)讓組件自動(dòng)更新,而不是必須用jQuery操作DOM。

GraphQL請求格式的另一個(gè)效果是增加了可見性:服務(wù)器可以看到每個(gè)被請求的字段。可以跟蹤字段的使用情況,看到客戶何時(shí)停止使用已廢棄的字段,這樣就知道何時(shí)可以刪除它們,而不用支持哪些應(yīng)該被摒棄的東西。像ApolloGraphOS和Stellate這樣的常用工具中都有跟蹤功能。

5.向前兼容

gRPC和GraphQL都有很好的向前兼容性;也就是說,很容易以不破壞現(xiàn)有客戶端的方式更新服務(wù)器。這對已經(jīng)過時(shí)的移動(dòng)應(yīng)用程序來說特別重要,但對于加載在用戶瀏覽器標(biāo)簽中的SPA在服務(wù)器更新后繼續(xù)工作來說,也是必要的。

在gRPC中,你可以通過對字段進(jìn)行數(shù)字排序、用新的數(shù)字添加字段,以及不改變現(xiàn)有字段的類型/數(shù)字來保持向前兼容。在GraphQL中,你可以添加字段,用`@deprecated"`指令廢除舊的字段(并讓它們發(fā)揮作用),并避免將可選參數(shù)改為必填。

6.傳輸

gRPC和GraphQL都支持服務(wù)器向客戶端傳輸數(shù)據(jù):gRPC有serverstreaming,GraphQL有Subscriptions和指令@defer、@stream和@live。gRPC的HTTP/2也支持客戶端和雙向流(盡管當(dāng)一方是瀏覽器時(shí)無法做到雙向)。HTTP/2還通過多路復(fù)用提高了性能。

gRPC有內(nèi)置的網(wǎng)絡(luò)故障重試,該功能在GraphQL中沒有直接體現(xiàn),而是在與之對應(yīng)的客戶端庫中支持網(wǎng)絡(luò)故障重試,比如ApolloClient的RetryLink。

gRPC無法使用大多數(shù)API代理,比如ApigeeEdge,它是以HTTP頭為操作對象的,而當(dāng)客戶端是瀏覽器時(shí),我們需要使用gRPC-Web代理或Connect(雖然現(xiàn)代瀏覽器確實(shí)支持HTTP/2,但沒有瀏覽器API允許對請求進(jìn)行足夠的控制)。默認(rèn)情況下,GraphQL不使用GET緩存:許多HTTP緩存都是在GET請求上工作的,而大多數(shù)GraphQL庫默認(rèn)使用POST。GraphQL有許多使用GET的選項(xiàng),包括將操作放在查詢參數(shù)中(當(dāng)操作字符串不太長時(shí)是可行的),建立時(shí)間持久化查詢(通常只用于私有API),以及自動(dòng)持久化查詢。緩存指令可以在字段級提供(整個(gè)響應(yīng)中最短的值被用于Cache-Control頭的`max-age')。

7.模式和類型

GraphQL有一個(gè)模式,服務(wù)器為客戶端開發(fā)人員發(fā)布并用于處理請求。它定義了所有可能的queries和mutations,以及所有的數(shù)據(jù)類型以及它們之間的關(guān)系。這種模式使來自多個(gè)服務(wù)的數(shù)據(jù)易于結(jié)合。GraphQL有schemastitching(將多個(gè)GraphQLAPI組合成一個(gè)代理schema的API)和federation(每個(gè)下游API聲明如何關(guān)聯(lián)共享類型,網(wǎng)關(guān)通過向下游API發(fā)出請求并結(jié)合結(jié)果自動(dòng)解決請求)的概念,用于創(chuàng)建一個(gè)超圖(所有數(shù)據(jù)的圖,整合了較小的子圖/部分模式)。也有一些庫將其他協(xié)議代理給GraphQL,包括gRPC。

伴隨著GraphQL的模式而來的是自檢系統(tǒng):以標(biāo)準(zhǔn)方式查詢服務(wù)器的能力,以確定其能力是什么。所有的GraphQL服務(wù)器庫都有自檢功能,還有一些基于自省的高級工具,如GraphiQL、請求提示與graphql-eslint和ApolloStudio,其中包括一個(gè)帶有字段自動(dòng)完成、提示、自動(dòng)生成文檔和搜索查詢的IDE。gRPC有自檢功能,但它沒有那么廣泛,使用它的工具也比較少。

GraphQL模式實(shí)現(xiàn)了反應(yīng)式的規(guī)范化客戶端緩存:因?yàn)槊總€(gè)(嵌套的)對象都有一個(gè)類型字段,類型在不同的查詢之間是共享的,我們可以告訴客戶端哪個(gè)字段是類型的ID,客戶端可以將數(shù)據(jù)對象進(jìn)行規(guī)范化存儲。這就實(shí)現(xiàn)客戶端的功能,比如查詢結(jié)果或更新會觸發(fā)對視圖組件的更新,而這些視圖組件依賴于包含相同對象的不同查詢。

gRPC和GraphQL類型之間的區(qū)別:

  • gRPC第3版(截至編寫時(shí)的最新版本)沒有必填字段:相反,每個(gè)字段都有一個(gè)默認(rèn)值。在GraphQL中,服務(wù)器可以區(qū)分一個(gè)值是否存在,模式(schema)可以表明一個(gè)參數(shù)必須存在,或者一個(gè)響應(yīng)字段將始終存在。
  • 在gRPC中,沒有標(biāo)準(zhǔn)的方法可以知道一個(gè)方法是否會變更狀態(tài)(與GraphQL相比,gRPC將queries和mutations分開)。
  • gRPC中支持Map類型,但GraphQL中不支持:如果你有一個(gè)數(shù)據(jù)類型,如`{[key:string]:T}`,需要通過JSON字符串類型實(shí)現(xiàn)。

GraphQL雖然具有模式和靈活查詢的特點(diǎn),但是對于公共API來說,速率限制更加復(fù)雜(對于私有API,允許列出持久查詢)。因?yàn)榭梢栽谝粋€(gè)請求中包含任意多的查詢,而且查詢可以任意嵌套的數(shù)據(jù),所以不能僅僅限制客戶端的請求數(shù)量。還需要對整個(gè)操作實(shí)施成本分析率限制,例如通過使用graphql-cost-analysis-cost-analysis庫將各個(gè)領(lǐng)域的成本相加,并將其傳遞給漏斗算法。

四、小結(jié)

以下將gRPc和GraphQL的異同以及優(yōu)缺點(diǎn)通過摘要的方式呈現(xiàn)給大家,方便比較分析。

1.gRPC和GraphQL的相似之處

  • 使用codegen的類型化接口
  • 抽離網(wǎng)絡(luò)層
  • 可以有JSON響應(yīng)
  • 服務(wù)器流媒體
  • 良好的前向兼容性
  • 可以避免過度獲取

2.gRPC和GraphQL的優(yōu)劣勢

(1)gRPC優(yōu)勢?

  • 二進(jìn)制格式

更快的網(wǎng)絡(luò)傳輸

更快的序列化、解析和驗(yàn)證

然而,比JSON更難查看和調(diào)試

  • HTTP/2

多重化

客戶端和雙向流媒體

  • 內(nèi)置重試和最后期限

(2)gRPC劣勢?

  • 需要代理或連接以從瀏覽器使用
  • 無法使用大多數(shù)API代理機(jī)構(gòu)
  • 沒有標(biāo)準(zhǔn)的方法可以知道一個(gè)方法是否會突變狀態(tài)

(3)GraphQL優(yōu)勢?

  • 客戶決定它希望返回哪些數(shù)據(jù)字段。結(jié)果是:沒有取不到的數(shù)據(jù)團(tuán)隊(duì)解耦提高辨識度
  • 更容易合并來自多種服務(wù)的數(shù)據(jù)
  • 進(jìn)一步發(fā)展自檢和工具化
  • 聲明性的數(shù)據(jù)取用
  • 反應(yīng)式的規(guī)范化客戶端緩存

(4)GraphQL劣勢

  • 如果我們已經(jīng)有了可以公開的gRPC服務(wù),那么增加一個(gè)GraphQL服務(wù)器就需要更多的后臺工作
  • HTTPGET緩存默認(rèn)不工作
  • 對于公共API來說,速率限制更為復(fù)雜
  • MAP類型不被支持
  • 低效的文本運(yùn)輸

3.如何取舍?

(1)服務(wù)器到服務(wù)器(Server-to-Server)

在服務(wù)器到服務(wù)器的通信中,低延遲往往很重要,而且有時(shí)需要更多類型的流,gRPC是明確的標(biāo)準(zhǔn)。然而,在有些情況下,我們可能會發(fā)現(xiàn)GraphQL的一些好處更為重要。

  • 我們正在使用GraphQLfederartion或模式拼接來創(chuàng)建所有業(yè)務(wù)數(shù)據(jù)的超圖,并決定由每個(gè)服務(wù)發(fā)布GraphQL子圖。我們創(chuàng)建了兩個(gè)超圖端點(diǎn):一個(gè)是由客戶調(diào)用的外部端點(diǎn),一個(gè)是由服務(wù)調(diào)用的內(nèi)部端點(diǎn)。在這種情況下,對于服務(wù)來說,暴露一個(gè)gRPCAPI可能是不值得的,因?yàn)樗鼈兌伎梢酝ㄟ^超圖方便地到達(dá)。
  • 服務(wù)的數(shù)據(jù)字段將發(fā)生變化,并讓字段級的使用情況可見,這樣就可以刪除被廢棄的字段(而不是永遠(yuǎn)維護(hù)它們)。

還有一個(gè)問題是,我們是否應(yīng)該自己做服務(wù)器到服務(wù)器的通信。對于數(shù)據(jù)獲取(GraphQL的查詢),這是獲得響應(yīng)的最快方式,但對于修改數(shù)據(jù)(變更),像MartinFowler的"同步調(diào)用被認(rèn)為是有害的",也就導(dǎo)致我們使用異步、事件驅(qū)動(dòng)的架構(gòu),在服務(wù)之間進(jìn)行編排或協(xié)調(diào)。微服務(wù)模式建議在大多數(shù)情況下使用后者,為了保持DX和開發(fā)速度,我們需要一個(gè)基于代碼的協(xié)調(diào)器而不是基于DSL的協(xié)調(diào)器。一旦在像Temporal這樣基于代碼的協(xié)調(diào)器中工作時(shí),就不再提出網(wǎng)絡(luò)請求--平臺會可靠處理這一切。在我看來,這就是未來。

(2)客戶端-服務(wù)器(Client-to-Server)

在客戶-服務(wù)器通信中,延遲很高。我們希望能夠在一次往返中獲得所有數(shù)據(jù),能夠靈活地為不同的視圖獲取對應(yīng)的數(shù)據(jù),并擁有強(qiáng)大的緩存能力,所以GraphQL是明顯的贏家。然而,在有些情況下,我們可以選擇使用gRPC來代替。

  • 如果已經(jīng)有可以使用的gRPCAPI了,那么再添加一個(gè)GraphQL服務(wù)器就不太值得了。
  • JSON并不適合這些數(shù)據(jù)(例如,我們正在發(fā)送大量的二進(jìn)制數(shù)據(jù))。

原文鏈接:https://stackoverflow.blog/2022/11/28/when-to-use-grpc-vs-graphql/

譯者介紹

崔皓,51CTO社區(qū)編輯,資深架構(gòu)師,擁有18年的軟件開發(fā)和架構(gòu)經(jīng)驗(yàn),10年分布式架構(gòu)經(jīng)驗(yàn)。曾任惠普技術(shù)專家。樂于分享,撰寫了很多熱門技術(shù)文章,閱讀量超過60萬?!斗植际郊軜?gòu)原理與實(shí)踐》作者。?

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2024-04-16 12:00:14

API系統(tǒng)

2023-11-09 09:13:48

GraphQLAPI 架構(gòu)

2023-03-10 15:03:37

Web 應(yīng)用程序API開發(fā)

2023-03-16 18:04:00

APIWeb 應(yīng)用程序開發(fā)

2022-08-02 19:03:19

RestAPI集成

2020-09-28 06:57:39

Node.jsGraphQLAPI

2019-12-09 08:00:00

GraphQLAPI架構(gòu)

2022-05-06 09:52:17

REST接口API

2024-06-24 00:20:00

API應(yīng)用程序接口

2021-05-07 09:06:55

GraphQLAPI 以太坊

2020-10-27 09:18:19

性能測試查詢

2023-08-01 11:14:07

開源Api軟件

2021-05-28 07:03:24

Vue GraphQL AP前端

2021-12-15 09:00:00

GraphQL安全漏洞

2021-04-21 09:04:43

開發(fā)SpringBoot框架

2023-08-30 15:49:51

GraphQLAPI 開發(fā)

2023-08-14 09:00:00

APIgRPCREST

2020-01-18 14:55:03

架構(gòu)運(yùn)維技術(shù)

2024-01-09 09:09:45

RESTGraphQL

2016-08-05 15:04:33

javascripthtmljs
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號