博客 / 詳情

返回

Dubbo3 服務原生支持 http 訪問,兼具高性能與易用性

作者:劉軍

作為一款 rpc 框架,Dubbo 的優勢是後端服務的高性能的通信、面向接口的易用性,而它帶來的弊端則是 rpc 接口的測試與前端流量接入成本較高,我們需要專門的工具或協議轉換才能實現後端服務調用。這個現狀在 Dubbo3 中得到了徹底解決,Dubbo 3.3 版本的最新 triple 協議,在持續提供高性能通信、面向接口易用性的同時,支持 http application/json 格式訪問,大幅簡化了開發測試、入口流量接入成本。

curl \
    --header "Content-Type: application/json" \
    --data '["Dubbo"]' \
    http://localhost:50051/com.example.demo.dubbo.api.DemoService/sayHello/

本文我們就以網關 http 流量接入為例,圍繞這個新特性升級展開講解。

實現 http 接入後端 dubbo 微服務

不論你開發的是什麼樣的產品(電子商城、管理系統、手機 app 等),絕大多數下產品的流量入口都會是 http,用户可能通過瀏覽器、手機移動設備、桌面軟件等來訪問產品。在這種情況下,如何將後端開發的 Dubbo 微服務集羣接入前端訪問設備就成為一個需要解決的問題,其實也就是 http 與 rpc 之間的轉換與連接問題。

總的來説,有中心化和去中心化兩種架構模式。其中,中心化接入模式更具通用性,對後端 rpc 協議、前端網關沒有太多特殊要求,但保證中心化應用的性能、穩定性是一個較大的挑戰;去中心化模式由於不需要維護入口應用,因此可適應更大流量、更大規模的集羣。

中心化接入方式

中心化接入方式的架構圖如下:

  • 在後端服務與前端設備之間有一層網關,負責流量過濾、路由、限流等流量管理工作。
  • 在後端集羣中有一個連接 http 與 dubbo 服務的 “統一微服務入口應用”(通常也叫做 BFF,即 Backend for Frontend)。

圖片

BFF 應用通常可以使用 Spring Web 等常用框架開發,應用發佈一系列的 http 服務,接收網關或前端設備流量,同時負責按需發起 dubbo 調用。

dubbo、triple 協議都支持這種接入架構。另外,在配置 BFF 應用調用 dubbo 服務時,可以使用普通的 dubbo 配置方式,也可以使用泛化調用等方式:

  • 配置接入 dubbo 協議時,使用泛化調用的優勢是可以避免對服務二進制包的依賴,實現配置動態生效的效果。
  • 配置接入 triple 協議時,可以使用 http 調用方式,同樣可避免對服務二進制包的依賴,實現配置動態生效的效果。

去中心化接入方式

與中心化架構相比,此方式並沒有太大的差異,唯一的區別在於不需要額外的 BFF 應用,我們可以在網關直接調用後端 dubbo 服務。

圖片

但這種方式對網關有特別要求。如果後端是 dubbo 協議的話,則要求網關具備 http -> dubbo 協議轉換的能力,但你會在接下來的文檔中發現,我們可以通過多協議發佈繞過協議轉換,讓網關直接通過 http 訪問後端服務;如果後端是 triple 協議,就會更簡單了,因為 triple 協議支持 application/json 格式的 http 請求。

使用不同的 rpc 協議也會影響架構選擇,triple 協議由於原生支持 HTTP 訪問,因此對兩種架構方式都可以無差別支持,並且接入原理上也會更簡單直接。而 dubbo 協議作為 Dubbo2 時代主推的協議,由於是基於 tcp 的二進制協議,因此在接入方式上存在一些不同。

我們將在接下來的兩篇文檔中介紹 dubbo、triple 兩種協議的具體前端流量接入方式,文檔同樣適用於中心化、去中心化架構。

不同 rpc 協議接入示例詳解

dubbo 協議接入方式

由於 dubbo 協議是基於 TCP 的二進制私有協議,因此更適合作為後端微服務間的高效 RPC 通信協議,這也導致 dubbo 協議對於前端流量接入不是很友好。在 Dubbo 框架中,有兩種方式可以幫助開發者解決這個問題:

  • 多協議發佈【推薦】 ,為 dubbo 協議服務暴露 rest 風格的 http 協議訪問方式,這種模式架構上會變得非常簡單,通用的網關產品即可支持。
  • 通過網關實現 http->dubbo 協議轉換,這種方式需要將 http 協議轉換為後端服務能識別的 dubbo 協議,要求網關必須支持 dubbo 協議。

同時發佈 http、dubbo 協議

如果我們能讓一個服務同時發佈 dubbo、http 協議,這樣後端調用是基於高效的 dubbo 二進制協議,同時瀏覽器、web服務等前端設施也可以用 http 協議訪問到相同的服務。 好消息是,Dubbo 框架支持為同一個服務發佈多個協議,並且支持客户端通過同一個端口以不同的協議訪問服務,如下所示:

圖片

為了實現同時發佈 dubbo、http 協議,我們只需要在配置文件中增加一行配置即可:

dubbo:
  protocol:
    dubbo: dubbo
    port: 20880
    ext-protocol: tri

增加 ext-protocol: tri 配置後,進程就可以在 20880 端口上提供 http 服務了,這點我們從之前的 triple 協議中有過具體瞭解了,啓用應用後就可以在 20880 端口訪問:

curl \
    --header "Content-Type: application/json" \
    --data '["Dubbo"]' \
    http://localhost:20880/org.apache.dubbo.protocol.multiple.demo.DemoService/sayHello

此時,網關就可以直接以 http 方式接入後端 dubbo 服務,任何 http 網關都可以非常容易接入,操作非常簡潔明瞭。

另外,關於 dubbo、triple 多協議發佈的完整示例源碼和講解可參見 apache/dubbo-samples 示例倉庫。

如果你對 /org.apache.dubbo.protocol.multiple.demo.DemoService/sayHello 格式的前端訪問路徑不滿意,可以選擇發佈 rest 風格的 http 接口,我們只需要在接口上增加註解即可(目前支持 Spring Web、JAX-RS 兩種註解)。如下所示,假設我們已經有一個名為 DemoService 的 dubbo 服務,只需要增加以下註解:

@RestController
@RequestMapping("/triple")
public interface DemoService {
    @GetMapping(value = "/demo")
    String sayHello();
}

這樣,就能發佈同時支持 dubbo、rest 兩種協議的服務,對於 http 網關接入更為簡單便捷,唯一成本是需要改造接口增加註解。

為 dubbo 協議服務增加了 http 訪問方式之後,就可以很容易的將 dubbo 服務接入網關了。

http 轉 dubbo 協議

如果您使用的是 Dubbo 3.3.x 版本,在決定考慮此方案之前,我們強烈推薦您仔細評估本文前一節的 多協議發佈方案。除非您因為某些特殊原因真的無法接受多協議發佈帶來的應用改造成本(實際上只是改一行配置而已),否則這個方案應該作為第二選擇。

如果要從網關接入後端 dubbo 服務,則前端的 HTTP 流量要經過一層 http -> dubbo 的協議轉換才能實現正常調用。

圖片

如上圖所示,從瀏覽器、手機或者 Web 服務器發送的 HTTP 請求,經過網關進行 http 到 dubbo 協議轉換,網關最終轉發 dubbo 協議到後端微服務集羣。因此,我們需要一個支持 dubbo 協議轉換的網關,來幫助實現協議轉發,以下是該架構下網關需要實現的幾個關鍵點:

  • 協議轉換,支持 http 到 dubbo 的協議轉換,包括參數映射。
  • 自動地址發現,支持 Nacos、Zookeeper、Kubernetes 等主流注冊中心,動態感知後端 dubbo 實例變化。
  • 結合 dubbo 協議的路由,如在發起 dubbo 協議調用時,支持按照特定規則地址篩選、傳遞附加參數到 dubbo 後端服務。

目前市面上支持 dubbo 協議接入、且對以上三點提供比較完善支持的開源網關產品眾多,包括大家 Higress、Apache APISIX、Apache Shenyu 等。接下來,讓我們通過一些示例來了解網關產品搭配 Dubbo 的具體使用方法吧:

  • Higress
  • Apache APISIX
  • Apache Shenyu

triple 協議接入方式

在官網 triple 協議規範中我們曾詳細介紹了 triple 對於瀏覽器、網關的友好性設計,其中非常重要的一點是 triple 同時支持跑在 HTTP/1、HTTP/2 上:

  • 在後端服務之間使用高效的 triple 二進制協議。
  • 對於前端接入層,則支持所有標準 HTTP 工具如 cURL 等以標準 application/json 格式請求後端服務。

接下來我們就看一下,對於前端 HTTP 流量而言,如何通過一些通用的網關產品快速接入後端的 triple 微服務體系。相比於上一節介紹的 dubbo 協議,使用 triple 協議後,不再需要泛化調用、http -> dubbo 協議轉換等步驟,任何主流的網關設備都可以通過 http 流量直接訪問後端 triple 協議服務。

原生 HTTP 接入

圖片

如上圖所示,從瀏覽器、手機或 Web 服務器過來的 HTTP 請求,網關可直接以 application/json 格式轉發給後端 Dubbo 服務,後端服務之間則繼續走 triple 二進制協議。由於進出網關的都是標準的 HTTP 流量,網關不需要做任何的私有協議轉換工作,不需要任何定製化邏輯,只需專注於流量路由等職責即可。

在真正的生產環境下,唯一需要網關解決的只剩下地址發現問題,即如何動態感知後端 triple 服務的實例變化? 好消息是,目前幾款主流的開源網關產品如 Apache APISIX、Higress 等普遍支持以 Nacos、Zookeeper、Kubernetes 作為 upstream 數據源。

以下我們以 Higress + Nacos + Dubbo 的典型用法為例,詳細説明整套機制的工作流程。

圖片

啓動示例應用

本示例完整源碼請參見 apache/dubbo-samples 中的 dubbo-samples-gateway-higress-triple 示例。

該示例中定義併發布了一個定義為 org.apache.dubbo.samples.gateway.api.DemoService 的 triple 服務:

public interface DemoService {
    String sayHello(String name);
}

接下來,我們演示如何啓動 Dubbo 服務,並使用 Higress 網關轉發請求到後端服務。

接入 Higress 網關

接下來,我們具體演示 Higress 網關接入應用的具體步驟。包括部署 Dubbo 應用、Nacos 註冊中心、Higress 網關等。

安裝 Higress 和 Nacos

以下示例部署在 Kubernetes 環境,因此請確保您已經連接到一個可用 Kubernetes 集羣。

  1. 安裝 Higress,參考 Higress 安裝部署文檔
  2. 安裝 Nacos,運行
kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/nacos/Nacos.yaml
啓動 Dubbo 應用

將以上示例應用打包為 docker image 後(這裏我們使用官方示例提前打包好的鏡像),以標準 Kubernetes Deployment 形式啓動應用:

kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/provider/Deployment.yaml

具體的部署文件定義如下:

apiVersion: apps/v1
kind: Deployment
metadata:
    name: gateway-higress-triple-provider
    namespace: default
    labels:
        app: gateway-higress-triple-provider
spec:
    replicas: 1
    selector:
        matchLabels:
            app: gateway-higress-triple-provider
    template:
        metadata:
            labels:
                app: gateway-higress-triple-provider
        spec:
            containers:
                -   name: gateway-higress-triple-provider
                    image: docker.io/allenyi/higress-triple:2.0.0
                    imagePullPolicy: IfNotPresent
                    ports:
            # 與容器暴露的端口一致
                        - containerPort: 50052
                    env:
            # 配置Nacos註冊中心地址,對應Dubbo服務配置中的${nacos.address:127.0.0.1}
                        - name: NACOS_ADDRESS
                          value: nacos-server.default.svc.cluster.local
通過 Higress 轉發請求到 Dubbo 服務

Higress 可以通過 McpBridge 來對接 Nacos 作為服務來源,在 K8s 集羣中 apply 以下資源來配置 McpBridge:

kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/mcp/mcpbridge.yaml

以上安裝的 McpBridge 資源的具體定義如下:

apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
  name: nacos-service-resource
  namespace: higress-system
spec:
  registries:
  - domain: nacos-server.default.svc.cluster.local
    nacosGroups:
    - DEFAULT_GROUP
    name: nacos-service-resource
    port: 8848
    type: nacos2

更多詳細配置參考 Higress McpBridge 配置説明。

接下來我們創建如下 Ingress,從而創建一條指向 Dubbo 服務的 HTTP 路由:

kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/ingress/Ingress.yaml

這樣,path 前綴為 /org.apache.dubbo.samples.gateway.api.DemoService 的請求就會被路由到我們剛剛創建的 Dubbo 服務上。

以上 apply 安裝的具體資源定義如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    higress.io/destination: gateway-higress-triple-provider.DEFAULT-GROUP.public.nacos
  name: demo
  namespace: default #與應用部署namespace保持一致
spec:
    ingressClassName: higress
    rules:
        - http:
              paths:
                  - backend:
                        resource:
                            apiGroup: networking.higress.io
                            kind: McpBridge
                            name: default
                    path: /org.apache.dubbo.samples.gateway.api.DemoService
                    pathType: Prefix

注意這裏通過註解 higress.io/destination 指定路由最終要轉發到的目標服務:gateway-higress-triple-provider,gateway-higress-triple-provider 為剛剛啓動 Dubbo 服務的應用名(這裏依賴 Dubbo3 默認註冊的應用粒度地址列表)。對於 Nacos 來源的服務,這裏的目標服務格式為:“服務名稱.服務分組.命名空間ID.nacos”,注意這裏需要遵循 DNS 域名格式,因此服務分組中的下劃線'_'被轉換成了橫槓'-'。命名空間未指定時,這裏默認值為"public"。

更多流量治理相關配置參考官網《Ingress Annotation 配置説明》 和 《通過 Ingress Annotation 實現高階流量治理》。

請求驗證

通過 cURL 訪問 Higress,可以實現對 triple 後端服務的調用:

$ curl "localhost/org.apache.dubbo.samples.gateway.api.DemoService/sayHello?name=HigressTriple"

"Hello HigressTriple"

這裏要運行 kubectl port-forward service/higress-gateway -n higress-system 80:80 443:443 將集羣內的 Higress 暴露出來才可訪問。

/org.apache.dubbo.samples.gateway.api.DemoService/sayHello/ 這種根據 Java 路徑名與方法直接暴露的訪問路徑,雖然可以很容易調通,但對於前端來説並不友好。接下來我們一起看一下如何發佈 REST 風格的 HTTP 服務。

REST 風格接口

在前面的示例中,如類似 http://127.0.0.1:9080/triple/demo/hello 會是更符合前端使用的訪問方式,要做到這一點,我們可以通過在 Higress 等網關配置 uri rewrite 重寫,實現前端 /triple/demo/hello 到後端 /org.apache.dubbo.samples.gateway.api.DemoService/sayHello/ 的映射。

除了配置網關 rewrite 重新規則之外,Dubbo 框架還為 triple 服務暴露 REST 風格的 HTTP 訪問路徑提供了內置支持,具體使用方式取決於你使用的是基於 “protobuf 的服務定義模式”,還是基於 “java 接口的服務定義模式”:

  • Java 接口模式(大部分 dubbo java 用户選擇),通過直接為 java 接口增加註解可以同時發佈 REST 風格服務,目前支持 Spring Web 與 JAX-RS 兩套註解標準。
  • Protobuf 模式,通過使用 grpc-gateway 可發佈 REST 風格服務。
為服務定義增加註解

通過為 Java 接口增加以下任意一種註解,即可發佈 triple 二進制、REST 風格的服務。這樣配置之後,對於同一個服務,你既可以使用標準二進制 triple 格式訪問服務,也可以使用 REST HTTP 方式以 JSON 格式訪問服務。

Spring Web 風格註解:

@RequestMapping("/triple/demo")
public interface DemoService {

    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    String sayHello(@RequestParam("name") String name);

}

在之前的示例 apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple 中已經啓用,可查看源碼瞭解實際用法。

這時我們的路由前綴配置如下,Nacos 地址配置與之前保持一致,path 前綴改為訪問更為友好的 /triple/demo:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    higress.io/destination: gateway-higress-triple-provider.DEFAULT-GROUP.public.nacos
  name: demo
  namespace: default
spec:
    ingressClassName: higress
    rules:
        - http:
              paths:
                  - backend:
                        resource:
                            apiGroup: networking.higress.io
                            kind: McpBridge
                            name: default
                    path: /triple/demo
                    pathType: Prefix

可以使用 /triple/demo/hello 訪問服務:

$ curl "localhost/triple/demo/hello?name=HigressTriple"

"Hello HigressTriple"

總結

本文展示了 Dubbo3  triple 協議是如何簡化從協議規範與實現上簡化開發測試、入口流量接入成本的,同時提供高性能通信、面向接口的易用性編碼。關於 Dubbo 3.3.0 正式版本,請持續關注社區最新動態。

本文相關參考鏈接請訪問:https://dubbo.apache.org

user avatar u_15690955 頭像 u_17468181 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.