編輯 | 言征
出品 | 51CTO技術棧(微信號:blog51cto)
gRPC 是一種高性能 RPC 框架,它取得了巨大的成功,并且徹底改變了我們部署 API 的方式。gRPC 和 protobuf 是一種性能極高的以契約為中心的框架,具有極其廣泛的語言支持。但它并非沒有缺點。制作一個需要代碼生成和多種編程語言支持的 RPC 框架肯定會出錯。隨著 gRPC 的使用時間接近十年,反思哪些方面可以做得更好是很重要的。
1.學習曲線
讓我們從極其挑剔開始。所謂的一元 RPC 是指客戶端向服務器發送單個請求并收到單個響應的調用。為什么 gRPC 必須使用這樣一個只有數學家才直觀理解的非標準術語來表示這一點?每次使用這個術語時,我都必須解釋一下。我有點厭倦了。
說到一元 RPC,其實現比它需要的更復雜。雖然 gRPC 的流式傳輸功能很強大,但它們為不需要流式傳輸的簡單 RPC 調用引入了復雜性。這損害了檢查 gRPC 調用的能力,因為現在每個一元 RPC 上都有框架,而這只對流式傳輸有意義。Protobuf 編碼已經足夠復雜了,所以我們不要在不需要的地方添加額外的 gRPC 框架。此外,它沒有通過我對任何 Web API 的“向朋友發送 cURL 示例”測試。向某人解釋如何使用 gRPC 實在是太煩人了。我已經說過“好的,但是服務器反射啟用了嗎?”很多次了。我只是厭倦了。
這種復雜性還通過強制代碼生成步驟滲透到工具中。這可能是一個障礙,尤其是對于重視運行時靈活性的動態語言。此外,一些開發人員可能不愿意采用需要額外構建步驟的技術。現代 Web 開發已經需要 20 個構建步驟,有時很難再增加一個步驟。
圖片
2.與 Web 的兼容性
對 HTTP/2 的依賴最初限制了 gRPC 的覆蓋范圍,因為并非所有平臺和瀏覽器都完全支持它。這種情況隨著時間的推移有所改善,但在某些環境中仍然構成挑戰。但即使有了 HTTP/2 支持,瀏覽器也避免添加處理 HTTP 尾部的方法,因此今天的瀏覽器仍然無法使用“原始” gRPC。gRPC-Web 通過避免使用尾部充當了這個問題的膏藥,但它通常需要“額外的東西”,比如運行支持 gRPC-Web 的代理。這很煩人。
HTTP/3 的采用較晚:HTTP/3 的采用延遲可能阻礙了 gRPC 充分利用該協議的性能和效率優勢。我個人受到將 gRPC 與 HTTP/2 結合使用時可能發生的隊頭阻塞問題的影響,如果能夠將 HTTP/3 與 gRPC 結合使用,可以完全消除此問題,那就太好了。看到一個推動多種語言支持 HTTP/2 的框架在努力用 HTTP/3 做同樣的事情,真是奇怪。
3.JSON 映射和 Prototext
另一個“時機”不對的領域是早期缺乏標準化的 JSON 映射。這讓習慣于基于 JSON 的 API 的開發人員更難使用 gRPC,而且我認為它從未從這種污名中恢復過來。在 protobuf 類型和 JSON 之間建立映射簡化了與現有工具和系統的集成和互操作性。當你說“是的,這是一種超高效的二進制格式……但如果你想調試,你可以設置這個標志并取回 JSON”時,你不會相信 Web 開發人員會有多高興。他們會興奮得不得了。太興奮了。無論如何,既然 protobuf 有了將 protobuf 類型映射到 JSON(反之亦然)的標準規則,我覺得protobuf 文本格式是一種不必要的復雜性。既然有了 JSON,我看不到文本格式的用例。所以讓我們拋棄文本格式吧。我們不需要它,如果其他人都不需要它,我愿意假裝它從未存在過。很酷吧?
4.有限的消息大小
大多數 Protobuf 編碼器/解碼器都希望完全解析整個消息并向消費者提供完整的響應,但內存是有限的,有時您可能需要更大的消息。有時您希望將這些較大消息的部分流式傳輸到其他地方,而不是將整個消息保存在內存中。因此,如果您想要上傳大文件,您將需要實現某種分塊。雖然分塊是處理大文件的合理解決方案,但 gRPC 中缺乏標準化方法可能會導致實現不一致并增加開發工作量。
作為演示,使用 gRPC 上傳文件如下所示:
syntax = "proto3";
package file_service;
service FileService {
rpc Upload(stream UploadRequest) returns(UploadResponse);
}
message UploadRequest {
string file_name = 1;
bytes chunk = 2;
}
message UploadResponse {
string etag = 1;
}
5.協議緩沖區
這是 protobuf 的優點,也是缺點。這個概念在 protobuf 中非常容易定義,但在實踐中,正確實現它的代碼可能很麻煩且容易出錯。雖然 gRPC 的創建者 Google 已經為他們的 API 找到了解決方案,但缺乏標準化方法使得其他人只能重新發明輪子。
你可能會想“Google 在其大多數 API 中使用 gRPC,因此顯然他們已經這樣做了”,您是對的。他們實際上有一個用于下載(可能很大的)文件的 gRPC 和 HTTP 版本。我們可以直接比較 gRPC 和 HTTP 版本,并且gRPC到目前為止要復雜得多。繼續比較鏈接的代碼。我會等待。
6.互聯網理論
我看到很多 gRPC/protobuf 社區都缺乏活動。一些網站上缺乏可見的活動可能會給人留下 gRPC 停滯不前或維護不積極的印象。這可能會阻礙潛在的采用者并導致社區增長放緩。這可能是因為選擇太多,很難在 GitHub 問題之外找到對 gRPC 感興趣的人,因為這種熱情可能會被視為煩人。
7.糟糕的工具
很長一段時間以來,當我看到代碼庫使用 protobuf 時,我都會發現一個奇怪的腳本,它以超級自定義的方式下載隨機的 protobuf 文件并將它們放置在隨機路徑中,然后對進行一系列超級復雜的調用protoc。只有谷歌會認為不解決依賴管理就是解決依賴管理問題的辦法。谷歌有自己非常谷歌式的管理依賴的方式,我們這些農民只能夢想著使用。
- 當生活給你錘子時,就把它變成錘子吧。
- 它可以更好(而且確實更好)
雖然我一直批評 gRPC,但我希望我的評論能起到建設性的作用。讀到本文末尾的人會知道,其中許多問題已經得到解決,或者至少正在得到解決!
一些 gRPC 實現已經支持 HTTP/3。ConnectRPC 使得使用 HTTP/3 和 gRPC 變得非常容易(我將在以后的文章中繼續介紹這一點)。
由于protobuf 規范具有與 JSON 的規范映射,我不再需要擔心文本格式。我真的希望每個人都忘記它的存在。文本格式的空間有限。我不是開玩笑。這是我最后一次承認它的存在。
如果您知道該去哪里找,gRPC 社區實際上非常活躍。例如,buf slack對我來說是一個很好的資源。您可能會發現我經常在這里閑逛并回答問題。
Buf CLI是一款出色的 gRPC 工具。它protoc不僅完全替代了 gRPC 的 linting、重大更改檢測、用于 gRPC 的 curl、與 Buf Schema Registry 的集成(哇,真正的依賴管理!),而且還添加了更多功能!此外,您熟悉和喜愛的 HTTP 工具也支持 gRPC,例如Postman、Insomnia和k6。
盡管 gRPC 取得了不可否認的成功,但承認該框架的缺點以確保其持續發展和改進仍然很重要。通過解決其學習曲線、兼容性問題、缺乏標準化和社區參與,我們可以釋放 gRPC 的全部潛力,使其成為所有開發人員更易于訪問和用戶友好的工具。