天天看點

Dubbo 3.0 前瞻之:常用協定對比及 RPC 協定新形态探索前言HTTP/1.1RESPDubbo2.0HTTP/2.0gRPCDubbo3.0Dubbo 社群總結

Dubbo 3.0 前瞻之:常用協定對比及 RPC 協定新形态探索前言HTTP/1.1RESPDubbo2.0HTTP/2.0gRPCDubbo3.0Dubbo 社群總結

作者 | 郭浩(項升)  阿裡巴巴經濟體 RPC 架構負責人

【Dubbo 3.0 前瞻系列】:

導讀:Dubbo 社群策劃了【Dubbo 雲原生之路】系列文章,和大家一起回顧 Apache Dubbo 産品和社群的發展,并展望未來發展。系列文章主要涵蓋 Dubbo 技術解讀、社群營運、應用案例解析三大部分。本文為系列第 4 篇。

前言

協定是 RPC 的基礎。資料在連接配接上以什麼格式傳輸,服務端如何确定收到請求的大小,同一個連接配接上能不能同時存在多個請求,請求如果出錯了應該怎麼響應……這些都是需要協定解決的問題。

從定義上講,協定通過定義規則、格式和語義來約定資料如何在網絡間傳輸。RPC 需要通信的兩端都能夠識别同一種協定。資料在網絡上以比特流的方式傳輸,如果本端的協定對端不識别,對端就無法從請求中擷取到有用資訊,就會出現雞同鴨講的情況,無法實作上層的業務需求。

Dubbo 3.0 前瞻之:常用協定對比及 RPC 協定新形态探索前言HTTP/1.1RESPDubbo2.0HTTP/2.0gRPCDubbo3.0Dubbo 社群總結

一個簡單的協定需要定義資料交換格式,協定格式和請求方式。

資料交換格式在 RPC 中也叫做序列化格式。常用的序列化有 JSON / Protobuf / Hessian 等,評價序列化優劣一般從三個次元:

  • 序列化後的位元組數組大小
  • 序列化和反序列化速度
  • 序列化後的可讀性

協定在選取序列化方式時,按照具體的需求在這三個次元中互相取舍。序列化後的數組越小,越節省網絡流量,但序列化過程可能更消耗時間。JSONXML 這類基于文本的序列化方式往往更容易被開發者接受,因為相比于一連傳的位元組數組,文本更容易被了解,在各層裝置中都能比較容易的識别,但可讀性提高的後果是性能大幅降低。

協定格式是和 RPC 架構緊密相關的,按照功能劃分有兩種:

  • 一種是緊湊型協定,隻提供用于調用的簡單中繼資料和資料内容;
  • 另外一種是複合型協定,會攜帶架構層的中繼資料用來提供功能上的增強,這類協定的一個代表就是 RSocket。

請求方式和協定格式息息相關,常見的請求格式有同步 Request/Response 和異步 Request/Response,差別是用戶端發出一個請求後,是否需要同步等待響應傳回。如果不需要等待響應,一個連結上就可以同時存在多個未完成的請求,這也被叫做多路複用。另外的請求模型有 Streaming ,在一次完整的業務調用中存在多次 RPC,每次都傳輸一部分資料,适合流資料傳輸。

有了這三個基本約定,就能實作一個簡單的 RPC 協定了。

Dubbo 3.0 前瞻之:常用協定對比及 RPC 協定新形态探索前言HTTP/1.1RESPDubbo2.0HTTP/2.0gRPCDubbo3.0Dubbo 社群總結

Dubbo3 的一個核心内容就是定義下一代 RPC 協定。除了基礎的通信功能,新協定還應該具有以下特性:

  • 統一的跨語言二進制格式
  • 支援 Streaming 和應用層全雙工調用模型
  • 易于擴充
  • 能夠被各層裝置識别

這裡我們對比一些常用的協定,來探索新協定的形态。

HTTP/1.1

HTTP/1.1 應該是應用最廣泛的協定,簡單清晰的文法,跨語言以及對原生移動端的支援都讓其成為了事實上最被廣泛接受的 RPC 方案。

然而從 RPC 協定的訴求上講, HTTP1.1 主要有以下幾個問題

  • 隊頭阻塞(HOL)導緻其在單連接配接的性能低下,盡管支援了 pipeline 但仍無法避免響應按序傳回;
  • 基于文本的協定每次請求都會重複攜帶很多繁雜無用的頭部資訊,浪費帶寬影響性能;
  • 純粹的 Request/Response 請求模型,無法實作 Server Push,隻能依靠用戶端輪詢,同樣 Streaming 的全雙工也是不安全的。
Dubbo 3.0 前瞻之:常用協定對比及 RPC 協定新形态探索前言HTTP/1.1RESPDubbo2.0HTTP/2.0gRPCDubbo3.0Dubbo 社群總結

RESP

RESP 是 Redis 使用的通信協定,其簡潔易于了解的格式也助力了 Redis 各語言用戶端的快速發展。但是這種類似 HTTP/1.1 的協定也存在着同樣的性能問題。

  • 序列化表達能力弱,通常還需要借助其他序列化方式輔助,然而協定中又不支援設定特定序列化方式,隻能依靠用戶端約定;
  • 同樣存在隊頭阻塞問題,pipeline 無法從根本上解決單連接配接性能問題;
  • Pub/Sub 在單連接配接情況下也有數量瓶頸。

Dubbo2.0

Dubbo2.0 協定直接定義在 TCP 傳輸層協定上,為協定功能定義提供了最大的靈活性,但同時也正是因為這樣明顯的靈活性優勢,RPC 協定普遍都是定制化的私有協定。

Dubbo 協定體 Body 中有一個可擴充的 attachments 部分,這給 RPC 方法之外額外傳遞附加屬性提供了可能,是一個很好的設計。但是類似的 Header 部分,卻缺少類似的可擴充 attachments,這點可參考 HTTP 定義的 Ascii Header 設計,将 Body Attachments 和 Header Attachments 做職責劃分。

  • Body 協定體中的一些 RPC 請求定位符如 Service Name、Method Name、Version 等,可以提到 Header 中,和具體的序列化協定解耦,以更好的被網絡基礎設施識别或用于流量管控;
  • 擴充性不夠好,欠缺協定更新方面的設計,如 Header 頭中沒有預留的狀态辨別位,或者像 HTTP 有專為協定更新或協商設計的特殊 packet;
  • 在 Java 版本的代碼實作上,不夠精簡和通用。如在鍊路傳輸中,存在一些語言綁定的内容;消息體中存在備援内容,如 Service Name 在 Body 和 Attachments 中都存在。

HTTP/2.0

HTTP/2.0 保留了 HTTP/1 的所有語義,在保持相容的同時,在通信模型和傳輸效率上做了很大的改進,主要也是為了解決 HTTP/1 中的問題。

  • 支援單條鍊路上的 Multiplexing,相比于 Request - Response 獨占鍊路,基于 Frame 實作更高效利用鍊路,StreamId 提供了上下文狀态,client 可以根據 StreamId 支援亂序 Response 傳回;
  • 頭部壓縮 HPACK,基于靜态表和動态表實作了 Header 緩存,減少傳輸資料量;
  • Request - Stream 語義,原生支援 Server Push 和 Stream 資料傳輸;
  • Binary Frame,二進制分幀,可以單獨處理 Header 和 Data。

HTTP/2.0 雖然克服了以上問題,但也存在着一些争議點,比如在 TCP 的上層進行流量控制的必要性,以及對 HTTP 語義通過 HPACK 相容是否過于繁瑣複雜。

gRPC

相比較于一些架構将應用層協定建構在裸 TCP 上,gRPC 選擇了 HTTP/2.0 作為傳輸層協定。通過對 Header 内容和 Payload 格式的限定實作上層協定功能。

下面是 gRPC 的一些設計理念:

  • Coverage & Simplicity,協定設計和架構實作要足夠通用和簡單,能運作在任何裝置之上,甚至一些資源首先的如 IoT、Mobile 等裝置;
  • Interoperability & Reach,要建構在更通用的協定之上,協定本身要能被網絡上幾乎所有的基礎設施所支援;
  • General Purpose & Performant,要在場景和性能間做好平衡,首先協定本身要是适用于各種場景的,同時也要盡量有高的性能;
  • Payload Agnostic,協定上傳輸的負載要保持語言和平台中立;
  • Streaming,要支援 Request - Response、Request - Stream、Bi-Steam 等通信模型;
  • Flow Control,協定自身具備流量感覺和限制的能力;
  • Metadata Exchange,在 RPC 服務定義之外,提供額外附加資料傳輸的能力。

在這樣的設計理念指導下,gRPC 最終被設計為一個跨語言、跨平台、通用的協定。功能上基本已經完全具備或可以輕易擴充出需要的新功能。然而我們知道,軟體工程沒有銀彈,相比較于裸 TCP 專有協定,極限性能上 gRPC 肯定是要差一些。但是對大部分應用來說,相比較于 HTTP/1.1 的協定,gRPC/HTTP2 已經在性能上取得了很大的進步,同時又兼顧了可讀性。

序列化上,gRPC 被設計成保持 payload 中立,但實際的跨語言場景需要一個強規範的接口定義語言來保證序列化結果的一緻。在 gRPC 的官方實作中,protobuf 和 json 分别用來支援性能場景和開發效率場景。從序列化方式的選擇到協定的各次元比較,基于 gRPC 擴充出新的協定是最優的選擇。

Dubbo3.0

Dubbo3.0 的協定基于 gRPC ,在應用層、異常處理、協定層負載均衡支援和 Reactive 支援上提供了擴充。主要有三個目标:

  • 在分布式大規模叢集場景下,提供更完善的負載均衡,以擷取更高性能和保證穩定性;
  • 支援 tracing/monitoring 等分布式标準擴充,支援微服務标準化以及平滑遷移;
  • Reactive 語義在協定層增強,能夠提供分布式 back-pressure 能力和更完善的 Streaming 支援。

除了協定層的支援,Dubbo3.0 新協定還包括易用性方面的支援,包括同時支援 IDL compiler 和 Annotation Compiler。用戶端将更完善地支援原生異步回調、Future 異步和同步調用,服務端将使用非反射調用,這十分顯著地提升了用戶端和服務端性能。從使用者遷移的角度,Dubbo 架構将提供平滑的協定更新支援,力求盡可能少的改造代碼或配置就能帶來成倍的性能提升。

Dubbo 社群

歡迎 Star 和共建:

https://github.com/apache/dubbo

總結

本文介紹了 RPC 協定的基礎概念,比較了常用的一些協定,并在這些協定的優劣對比後提出了 Dubbo3.0 協定。Dubbo3.0 協定将在易用性、跨平台、跨語言、高性能等方面取得更大的領先。預計在 2021 年 3 月,Dubbo3.0 協定将完整支援,請大家拭目以待。

阿裡巴巴雲原生 關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公衆号。”