gRPC 爲什麼比基於 JSON 的 REST API 快

兩個主要原因。

看了不少關於 REST 與 JSON 和 gRPC 的性能基準測試。其中一些測試顯示,gRPC 將每個請求的延遲減少了一半。

那麼,它爲什麼這麼快呢?🤔

⚡ 第一個原因是 HTTP/2。

HTTP/1.1 的請求和響應是同步的,一次只能處理一個請求。而 HTTP/2 請求是異步的,可以同時發送多個請求,不需要等待前一個請求的響應。減少了等待前一個請求完成的時間,同時連接複用,也避免了 TCP 和 TLS 握手的時間。

這對 gRPC 來說是一個重要因素,因爲 gRPC 在底層利用了 HTTP/2 協議。

雖然對用戶來說可能看起來只是簡單的 RPC 調用,但它在底層使用的是 HTTP。

📦 第二個原因是 Protobuf。

HTTP/2 + JSON 本身就可以相當快,但使用 Protobuf 代替 JSON 可以進一步推動性能提升。

像 JSON 一樣,Protobuf 是一種用於交換數據的結構化消息格式,但最大的不同是 Protobuf 是基於二進制的。

作爲基於二進制的,Protobuf 在網絡傳輸數據時更加緊湊。

以下是一個簡單的對比示例。

假設我們有一個表示用戶信息的結構:

{
  "id": 12345,
  "name""Alice",
  "email""alice@example.com",
  "isAdmin": true,
  "scores": [85, 92, 88]
}

對應的 Protobuf 定義如下:

syntax = "proto3";

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
  bool isAdmin = 4;
  repeated int32 scores = 5;
}

數據編碼後的對比

我們將上述數據分別序列化爲 JSON 和 Protobuf,得到如下結果:

  1. JSON 格式

序列化後的 JSON 數據如下(未壓縮):

{
  "id": 12345,
  "name""Alice",
  "email""alice@example.com",
  "isAdmin": true,
  "scores": [85, 92, 88]
}

JSON 字符串的總大小爲 115 字節。

  1. Protobuf 格式

序列化後的 Protobuf 數據(二進制形式,無法直接閱讀,但可以解析爲字節數組表示):

08 b9 60 12 05 41 6c 69 63 65 1a 12 61 6c 69 63 65 40 65 78 61 6d 70 6c 65 2e 63 6f 6d 20 01 2a 03 55 5c 58

Protobuf 字節數組的總大小爲 37 字節。

JSON 採用了文本格式,包含大量描述性的標籤(如 "id"、"name" 等)以及符號(如引號、逗號等),如果有 json 字符串的嵌套可能還有一堆的斜槓。而二進制格式,無需描述性標籤,僅包含數據和簡潔的字段標識符(字段 ID)。

Protobuf 使用二進制編碼和字段號(如 id = 1)來標識數據,而 JSON 使用鍵值對字符串描述數據結構,增加了額外開銷。所以,Protobuf 的數據大小顯著小於 JSON,尤其是字段較多、數據量較大時,差距會更明顯。

因此,在帶寬敏感或高性能需求的場景中,Protobuf 優勢突出。

而且 Protobuf 在序列化和反序列化過程中也比 JSON 快得多。據測試顯示 Protobuf 序列化速度比 JSON 快 10 到 100 倍。

2kMxjg

JSON 需要解析文本中的每個字符,尤其是長字符串和數字字段時,會面臨較高的開銷。解析 JSON 數據時,必須將文本解析爲原始數據類型,並且每次解析時需要處理字符串鍵名、符號(如括號、逗號等),這比直接解析二進制數據慢得多。

因此,Protobuf 不僅傳輸速度更快,而且處理速度也更快。

💎 但性能並非沒有代價。

雖然 gRPC 有很多優勢,甚至超越了性能,它也帶來了一些複雜性。

🔀 複雜性:負載分配

和 HTTP/2 一樣,gRPC 默認會爲多個請求重用連接。如果主要依賴基於連接的負載均衡,這種多路複用可能導致負載分配不均衡。

使用第七層負載均衡器或客戶端負載均衡可以解決這個問題,但需要考慮這一點。

🧰 複雜性:故障排除

雖然用於故障排除 gRPC 服務的工具集正在增長,但它仍然不如 REST + JSON 那樣容易。

gRPC 使得執行臨時請求、捕獲和調試有效載荷、驗證端點等變得更加困難。

📄 複雜性:契約

Protobuf 的一個優勢是清晰的契約。每個人都使用相同的 proto 文件來生成序列化和反序列化的包。

這種方法很棒,因爲它消除了誤解,但在分發和版本控制該文件時可能會變得複雜,尤其是當試圖將其分發給外部用戶時。

💡 總結

如果你需要性能提升,或者你的環境能夠處理 gRPC 帶來的複雜性,那麼 gRPC 是一個很好的方法。

如果你對 REST + JSON 感到滿意,並且對 gRPC 的複雜性感到困擾,那也沒關係;REST 依然很多人在使用。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/-LwAhWBy9y0dkzFbIB9YQA