博客 / 詳情

返回

如何用一個端口同時暴露 HTTP1/2、gRPC、Dubbo 協議?

本文我們將介紹 Apache Dubbo 靈活的多協議設計原則,基於這一設計,在 Dubbo 框架底層可靈活的選用 HTTP/2、HTTP/REST、TCP、gRPC、JsonRPC、Hessian2 等任一 RPC 通信協議,同時享用統一的 API 與對等的服務治理能力。同時,我們還介紹了 Dubbo 的單端口多協議能力,也就是在單個端口同時監聽、處理多個協議,這對於簡化多協議同時發佈的場景非常有用。

不綁定 RPC 協議的設計原則

Dubbo 框架不綁定任何通信協議,你可以根據業務場景選擇 HTTP/2 通信協議,也可以選用 HTTP/REST、TCP(Dubbo2)、gRPC、JsonRPC、Hessian2 等官方支持的通信協議,如果以上協議都不能滿足需求,還可以非常方便的通過定製方式接入自定義協議。如果你想在一個應用內使用多個協議,也可以非常容易的做到,比如一個接口使用 HTTP/2 通信,另一個接口使用 TCP 通信,一個應用內發佈或調用多個使用不同協議的服務。

圖片

通過 Dubbo 框架的多協議支持,你可以做到:

  • 將任意通信協議無縫地接入 Dubbo 服務治理體系。Dubbo 體系下的所有通信協議,都可以享受到 Dubbo 的編程模型、服務發現、流量管控等優勢。比如 gRPC over Dubbo 的模式,服務治理、編程 API 都能夠零成本接入 Dubbo 體系。
  • 兼容不同技術棧,業務系統混合使用不同的服務框架、RPC 框架。比如有些服務使用 gRPC 或者 Spring Cloud 開發,有些服務使用 Dubbo 框架開發,通過 Dubbo 的多協議支持可以很好的實現互通。
  • 讓協議遷移變的更簡單。通過多協議、註冊中心的協調,可以快速滿足公司內協議遷移的需求。比如如從自研協議升級到 Dubbo 協議,Dubbo 協議自身升級,從 Dubbo 協議遷移到 gRPC,從 HTTP 遷移到 Dubbo 協議等。

官方接入的主流協議

HTTP/2 (Triple)

Triple 協議是 Dubbo3 發佈的面向雲原生時代的通信協議,它基於 HTTP/2 並且完全兼容 gRPC 協議,原生支持 Streaming 通信語義,自 Triple 協議開始,Dubbo 還支持基於 Protobuf 的服務定義與數據傳輸。Triple 具備更好的網關、代理穿透性,因此非常適合於跨網關、代理通信的部署架構,如服務網格等。Triple 協議的核心特性如下:

  • 支持 TLS 加密、Plaintext 明文數據傳輸
  • 支持反壓與限流
  • 支持 Streaming 流式通信

在編程與通信模型上,Triple 協議支持如下模式:

  • 消費端異步請求(Client Side Asynchronous Request-Response)
  • 提供端異步執行(Server Side Asynchronous Request-Response)
  • 消費端請求流(Request Streaming)
  • 提供端響應流(Response Streaming)
  • 雙向流式通信(Bidirectional Streaming)

TCP (Dubbo2)

Dubbo2 協議是基於 TCP 傳輸層協議之上構建的一套 RPC 通信協議,由於其緊湊、靈活、高性能的特點,在 Dubbo2 時代取得了非常廣泛的應用,是企業構建高性能、大規模微服務集羣的關鍵通信方案。在雲原生時代,我們更推薦使用通用性、穿透性更好的 Triple 協議。

gRPC

你可以用 Dubbo 開發和治理微服務,然後設置使用 gRPC 協議進行底層通信。但為什麼要這麼做那,與直接使用 gRPC 框架對比有什麼優勢?簡單的答案是,這是使用 gRPC 進行微服務開發的常用模式,具體請往下看。

gRPC 是谷歌開源的基於 HTTP/2 的通信協議,如同我們在產品對比[1]文檔中提到的,gRPC 的定位是通信協議與實現,是一款純粹的 RPC 框架,而 Dubbo 定位是一款微服務框架,為微服務實踐提供解決方案。因此,相比於 Dubbo,gRPC 相對欠缺了微服務編程模型、服務治理等能力的抽象。

在 Dubbo 體系下使用 gRPC 協議 (gRPC over Dubbo Framework) 是一個非常高效和輕量的選擇,它讓你既能使用原生的 gRPC 協議通信,又避免了基於 gRPC 進行二次定製與開發的複雜度 (二次開發與定製 gRPC,是很多企業規模化實踐後證實不可避免的環節,Dubbo 框架替開發者完成了這一步,讓開發者可以直接以最簡單的方式使用 gRPC)。

REST

微服務領域常用的一種通信模式是 HTTP + JSON,包括 Spring Cloud、Microprofile 等一些主流的微服務框架都默認使用的這種通信模式,Dubbo 同樣提供了對基於 HTTP 的編程、通信模式的支持。

其他通信協議

除了以上介紹的幾種協議之外,你還可以將以下協議運行在 Dubbo 之上。對 Dubbo 而言,只需要修改一行簡單的配置,就可以切換底層服務的通信協議,其他外圍 API 和治理能力不受影響。

  • Hessian2
  • Thrift
  • JsonRPC

單端口多協議

自 Dubbo 3.2 版本開始,Dubbo 提供了單個端口上的協議複用能力,通過調整 Protocol 配置即可實現。

比如在開啓 HTTP/2 (Triple) 協議 或 gRPC 協議後,如我們同時啓動端口複用,還可以在相同的端口上為服務增加 TCP (Dubbo2) 協議、Qos 協議的支持。這些所有流量的入口都在一個統一 port 端口, Dubbo 框架負責在端口之上識別不同的 RPC 協議,並進行處理器分發,從而實現單個端口上的協議複用。

對於需要處理多個協議的場景,端口複用非常有價值。它可以用於服務的協議遷移,並且可以節約端口以及相關的資源,減少運維的複雜性等。

實現原理

以下是端口複用實現的原理圖

圖片

  • 在服務的創建階段,通過從 Config 層獲取到服務導出的協議配置從而創建不同的 Protocol 對象進行導出。在導出的過程中,如果不是第一次創建端口複用的 Server,那麼 Exchanger 會將 Protcol 層傳遞的數據保存到 Server,用於後續處理該協議類型的消息。
  • 當客户端的消息傳遞過來後,首先會通過 Server 傳遞給 ProtocolDetector,如果完成了識別,那麼就會標記該客户端為對應的協議。並通過 WireProtocol 配置對應的處理邏輯,最後交給 ChannelOperator 完成底層的 IO 框架和對應的 Dubbo 框架的處理邏輯的綁定。
  • 以上的協議識別完成之後,Channel 已經確定瞭如何處理遠程的客户端消息,通過對應的 ServerPipeline 進行處理即可(在處理的過程中也會根據配置信息決定消息的處理線程)。

使用場景

以下是幾種常見的使用場景。

  • 最常用的是用於服務發現。這允許應用程序通過網絡發現服務,然後使用同一端口與它們通信,有助於降低網絡通信的複雜性,並使其更易於管理。
  • 可以用於負載平衡。這允許應用程序在多個遠程服務或服務集羣之間平衡負載,有助於提高服務的可擴展性、可靠性和可用性。
  • 可以用於服務監控。這允許應用程序監視遠程服務的運行狀況,並在服務出現故障或變得不可用時發出警報,有助於確保服務的可用性並減少停機時間。
參考用例:https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification

使用方式

在同一主機上部署多個服務或需要通過負載均衡器訪問多個服務。

關於 Dubbo 支持的配置方式 配置説明[2]

服務多協議導出

ext-protocol 參數支持配置多個不同的協議,協議之間通過","進行分隔。

xml 配置

<dubbo:protocol name="dubbo" port="-1" ext-protocol="tri,"/>
<bean id="greetingService" class="org.apache.dubbo.demo.provider.GreetingServiceImpl"/>
<dubbo:service delay="5000" version="1.0.0" group="greeting" timeout="5000" interface="org.apache.dubbo.demo.GreetingService" ref="greetingService" protocol="dubbo"/>

API 配置

ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1);

config.setExtProtocol(CommonConstants.DUBBO+",");

yaml 配置

dubbo:
  application:
    name: dubbo-springboot-demo-provider
  protocol:
    name: tri
    port: -1
    ext-protocol: dubbo,

properties 配置

dubbo.protocol.name=tri
dubbo.protocol.ext-protocol=dubbo,
dubbo.protocol.port=20880

Qos 接入

Qos 模塊導入

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-qos</artifactId>
</dependency>

完成 Qos 模塊的導入之後,相關的配置項可參考 Qos 操作手冊[3]進行配置。

默認情況下,基於端口複用的 Qos 服務在模塊導入後是啓動的。

Qos 使用

將 Qos 協議接入到端口複用的場景下,需要在建立連接之後,客户端先向服務端發送消息,對比將 Qos 協議通過單個端口提供服務,端口複用版的 Qos 協議在處理 telnet 連接的情況下需要用户執行一些操作,完成協議識別(二選一)。

1.直接調用命令

直接調用 telnet 支持的命令也可以完成識別,在用户不熟悉的情況下可以調用 help 指令完成識別

圖片

2.發送 telnet 命令識別

通過 telnet 命令建立連接之後,執行以下幾個步驟:

  1. 使用 crtl + "]" 進入到 telnet 交互界面(telnet 默認的 escape character)
  2. 調用 "send ayt" 向服務端發送特殊識別字段(為 telnet 協議的一個特殊字段)
  3. 回車完成消息發送並進入到 dubbo 的交互界面

圖片

服務引用

以 dubbo-samples-port-unification[4]中的例子作為基礎, 引用不同協議的服務和非端口複用情況下的配置是一致的,下面通過 Consumer 端的 InvokerListener 輸出調用過程中的 URL 信息。

ReferenceConfig<GreetingService> reference = new ReferenceConfig<>();
reference.setInterface(GreetingService.class);
reference.setListener("consumer");
reference.setProtocol(this.protocol);
// reference.setProtocol(CommonConstants.DUBBO);
// reference.setProtocol(CommonConstants.TRIPLE);

圖片

總結

對於微服務實踐中經常會遇到的多協議通信的場景,Dubbo 不綁定協議的設計讓用户可以靈活的選擇通信協議,整個協議選擇過程對上層 API 編碼與運維治理完全透明;對於要在一個集羣內同時處理多個協議的場景,Dubbo 的多協議支持也可以從容應對,而單端口的多協議複用支持進一步簡化了這一過程。

在接下來的一篇文章中,我們將詳細介紹如何在 Dubbo 框架中開發 gRPC 協議通信的服務,極大的簡化了 gRPC 微服務開發成本,避免了二次開發,為原生 gRPC 提供了統一的編程 API 與開箱即用的服務治理能力。

相關鏈接:

[1]產品對比https://cn.dubbo.apache.org/zh-cn/overview/what/xyz-difference/
[2]配置説明https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/r...
[3]Qos 操作手冊https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/r...
[4]dubbo-samples-port-unificationhttps://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification

作者:華鍾明

原文鏈接

本文為阿里雲原創內容,未經允許不得轉載。

user avatar xiaoemo_5df065196d684 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.