本篇為同程藝龍旅行網 Apache Dubbo 的實踐案例總結,感興趣的朋友可以訪問官網了解更多詳情,或搜索關注官方微信公眾號
Apache Dubbo跟進最新動態,
作者資訊:
- 嚴浩:同程藝龍高級開發,負責服務治理相關作業, Apache Dubbo Committer,
- 胥皓:同程藝龍高級開發,負責服務治理相關作業,
Dubbo3在同程旅行的實踐
背景
在微服務發展初期,市場上還沒有成熟和流行的 RPC 框架,我們公司內部自研開發了一套名為 DSF (Distributed Service Framework) 的 RPC 框架,支撐起了公司業務的高速發展,但是隨著技術的快速迭代和人員的不斷變更,開發者既要修復之前的 BUG 又要跟上技術的更新,開發維護成本越來越高,另一方面,現在應用程式都在往云原生方向發展與設計,公司也在這方面做出探索,因此公司微服務框架的演進已經到了岔路口,是全新升級原有的 SDK,還是選擇擁抱開源?
考慮到升級現有的 SDK 在一段時間之后可能依然會面臨現在的問題,最后我們選擇了擁抱開源,在一番調研之后我們選擇了 Dubbo3 作為公司的下一代 RPC 框架,擔任微服務治理體系的資料面,
目前 Dubbo3 在公司的落地開發作業已經完成,通過本文我們對公司內部 Dubbo3 的實踐及收益做了深入總結,
Dubbo3 核心功能介紹
Dubbo 社區關于 Dubbo 3 的檔案和資料越來越完善,以下是我們從社區參考的一些內容,

Dubbo3 被社區寄予厚望,將其視為下一代云原生服務框架打造,Dubbo3 提供的核心特性串列,主要包括四部分,
- 全新服務發現模型,應用粒度服務發現,面向云原生設計,適配基礎設施與異構系統;性能與集群伸縮性大幅提升,
- 下一代 RPC 協議 Triple,基于 HTTP/2 的 Triple 協議,兼容 gRPC;網關穿透性強、多語言友好、支持 Reactive Stream,
- 統一流量治理模型,面向云原生流量治理,SDK、Mesh、VM、Container 等統一治理規則;能夠支持更豐富的流量治理場景,
- Service Mesh,在最新的3.1.0的版本中支持Sidecar Mesh 與 Proxyless Mesh,提供更多架構選擇,降低遷移、落地成本,
Dubbo3 的核心功能點(如應用級服務發現以 ip、port 為區分實體)和公司內部的服務模型一致,極大地減少了我們的適配作業,還有在 Service Mesh 中對 Sidecar Mesh 與 Proxyless Mesh 的支持也將減少后續公司對 Mesh 方案的探索成本,包括 Dubbo3 在多語言體系的發展也為異構架構提供了支撐,
總的來說,Dubbo3 非常契合公司的技術體系和后續的發展方向,此外,Dubbo 在開發者中的熟悉度、社區的高活躍度和完善的檔案建設也都能為推動 Dubbo3 的使用帶來不少的幫助,
方案調研
在了解了 Dubbo3 的核心功能和基本作業原理之后我們開始前期作業階段,
公司內部存在微服務體系 RPC 框架 DSF 和承擔服務發現、路由、上下負載等功能的控制中心,如果讓用戶直接切換到 Dubbo3 使用完全隔離的一套微服務體系會對用戶帶來高額的升級和切換成本,所以我們選擇用 Dubbo3 替換之前的 DSF 框架作為資料面,將 Dubbo3 接入當前的微服務控制中心,同時要求 Dubbo3 支持原有 DSF 框架的私有協議,與 DSF 框架能夠相互發現和呼叫,進一步降低用戶升級成本,
這樣用戶在編程習慣上和 Dubbo3 的使用完全保持一致,在服務治理上(如上下負載、同中心路由、實體標簽等功能)的使用與 DSF 保持一致,由于協議兼容,新的 Dubbo3 應用和原有 DSF 應用之間也能實作互相發現和呼叫,
要完成這個目標,需要去拓展 Dubbo3 SDK 的注冊模塊支持從現有的控制中心進行服務注冊與發現、擴展自定義協議與 DSF 服務相互呼叫,借助于Dubbo 強大的插件機制,我們在沒有修改 Dubbo 框架任何代碼的基礎上輕松地完成了這個目標,用戶只需要引入 Dubbo 3.0 以上版本的 SDK 和我們開發的插件包即可,
整體的架構流程如下:

Dubbo3 落地的方案需要滿足以下三點要求:
- Dubbo3 要接入現有的控制中心,由控制中心完成服務注冊發現和服務治理功能;
- Dubbo3 能夠和 DSF 能夠相互呼叫,滿足此要求需要兩個框架能夠互相服務發現并且協議能夠兼容;
- 通過插件機制完成所有功能,不能修改 Dubbo 原始碼,用戶可以自由地升級 Dubbo3 SDK 的版本;
服務注冊發現兼容
既然需要將 Dubbo3 的應用級注冊接入到控制中心,而且需要與 DSF 服務進行服務發現,就需要了解 Dubbo3 應用級發現的流程才能對其進行更好的拓展,
應用級服務發現核心原理

我們從 Dubbo 最經典的作業原理圖說起,Dubbo 從設計之初就內置了服務地址發現的能力,Provider 注冊地址到注冊中心,Consumer 通過訂閱實時獲取注冊中心的地址更新,在收到地址串列后,Consumer 基于特定的負載均衡策略發起對 Provider 的 RPC 呼叫,
在這個程序中:
- 每個 Provider 通過特定的 key 向注冊中心注冊本機可訪問地址;
- 注冊中心通過這個 key 對 Provider 實體地址進行聚合;
- Consumer 通過同樣的 key 從注冊中心訂閱,以便及時收到聚合后的地址串列;
可以看到介面級服務發現是以介面為維度進行服務注冊的,并在注冊資料上攜帶了服務的配置和元資料,這種方式簡單易用而且可以輕松實作應用、介面、方法粒度的服務治理,但由此帶來的注冊資料的放大問題會給注冊中心造成較大壓力,還有就是與現在云原生的服務模型并不兼容,不能與 Kubernetes 兼容,
面對這些不足,在 Dubbo3 架構下社區認真思考了兩個問題:
- 如何在保留易用性、功能性的同時,重新組織 URL 地址資料,避免冗余資料的出現,讓 Dubbo 3 能支撐更大規模集群水平擴容?
- 如何在地址發現層面與其他的微服務體系如 Kubernetes、Spring Cloud 打通?

最終,社區給出的方案也是非常巧妙和經典,將之前介面級服務的資料拆成兩部分,屬于實體模型的 ip 和 port 注冊到注冊中心,而屬于業務屬性的 RPC 元資料和 RPC 服務配置統一由 Dubbo Provider 的 MetadataService RPC 服務提供或者由元資料中心提供,在服務消費端和提供端之間建立了一條內置的 RPC 服務資訊協商機制,也稱為"服務自省",全新的應用級服務發現模型,相比之前介面級別單機記憶體下降 50% 且極大的減少了注冊中心的壓力,
還有一個問題是換成了應用級服務發現之后,Consumer 是如何知道訂閱的介面是屬于哪一個服務的?因為 Dubbo 的編程模型是以介面為維度的,Dubbo3 提供了兩種解決方案:一是從元資料中心存盤介面和應用名的映射關系,二是通過 Consumer 在介面上通過 providerBy 配置手動指定服務提供方的名稱,
兼容方案
如果是 Dubbo Consumer 呼叫 Dubbo Provider,我們只需要按部就班參考其他應用級別服務發現的插件比如 Zookeeper、Nacos 開發就可以完成此功能,如果 DSF Client 要呼叫 Dubbo Provider 我們是將兼容邏輯放在了控制中心,避免用戶 SDK 的升級成本,剩下的兼容流程只有 Dubbo Consumer 呼叫 DSF Server 了,因為要求盡量不要修改 Dubbo 框架的原始碼,所以這里的兼容邏輯我們只能在注冊中心的插件中完成,
上面介紹應用級服務發現的核心原理的時候提到應用級服務發現有 3 個關鍵的步驟
- 通過元資料的 mapping 獲取介面對應的服務名或者通過介面配置中的 providerBy 指定;
- 通過服務名獲取實體串列,實體以 ip、port 為維度,并且在實體資訊中攜帶元資料的 revision;
- 呼叫 Dubbo Provider 的 MetaService 獲取實體的元資料資訊,組裝介面資料;
Dubbo 服務 呼叫 DSF 服務兼容流程的第一步非常簡單,因為 DSF 并沒有介面與服務名的 mapping 資料,所以通過 providerBy 指定介面所屬的 DSF 服務名,第二步因為 DSF 服務的注冊模型也是應用級的,實體的資料完全可以兼容這一部分也很簡單,最關鍵的一步在于如何獲取 DSF 服務的元資料,很顯然現有的 DSF 服務并不具有 MetaService 的介面,
上面提到 Dubbo3 支持兩種方式獲取實體的元資料,默認就是從 Dubbo Provider 的 MetaService 獲取實體的元資料資訊,也支持從元資料中心獲取實體的元資料資訊,只需要將實體的 dubbo.metadata.storage-type 屬性設定為 remote 即可,而 DSF 服務正好發布了 API 的契約資料到控制中心用作服務測驗和尋址兼容,完全可以將 DSF 的契約資料轉換為 Dubbo 的元數據的格式,滿足服務發現的流程,
以下為 Dubbo Consumer 發現 DSF 服務的流程

完成服務發現的兼容之后,用戶在呼叫 DSF 服務的時候僅需要在介面上通過 providerBy 指定介面對應的服務即可,使用成本極低,
協議兼容與服務治理
協議兼容
完成服務發現的相互兼容之后,離 Dubbo 與 DSF 服務的相互呼叫的目標只剩最后一塊拼圖,在插件中實作 DSF 協議即可,
相比服務發現的各種資料兼容,協議的兼容比較清晰,只需要根據 Dubbo 協議擴展說明進行自定義協議擴展完成 DSF 資料格式兼容即可,
Dubbo 協議擴展需要實作以下介面:
org.apache.dubbo.rpc.Exporterorg.apache.dubbo.rpc.Invokerorg.apache.dubbo.rpc.Protocol

當用戶呼叫 refer() 所回傳的 Invoker 物件的 invoke() 方法時,協議需相應執行同 URL 遠端 export() 傳入的 Invoker 物件的 invoke() 方法,其中,refer() 回傳的 Invoker 由協議實作,協議通常需要在此 Invoker 中發送遠程請求,export() 傳入的 Invoker 由框架實作并傳入,協議不需要關心,也就是說服務提供方在容器啟動的時候就進行服務的暴露,而服務呼叫方需要通過協議進行Invoker的呼叫,我們的擴展如下:

最后完成的效果如下,用戶只需要在 pom 中引入 Dubbo3 以上的任意版本和開發的插件,配置上指定注冊中心地址和協議為 dsf 即可,其他使用方式和 Dubbo3 保持一致,
<properties>
<dubbo.version>3.0.11</dubbo.version>
<dubbo-dsf.version>1.0.0</dubbo-dsf.version>
</properties>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.ly.dsf</groupId>
<artifactId>dubbo-dsf-extensions-all</artifactId>
<version>${dubbo-dsf.version}</version>
</dependency>
組態檔
# 注冊地址為控制中心
dubbo.registry.address=dsf://{address}
# 協議指定 dsf
dubbo.protocol.name=dsf
dubbo.consumer.protocol=dsf
服務治理
Dubbo3 有非常強大的流量治理的功能,同時我們內部的控制中心也有服務治理的功能,部分功能也有重合,
對于這部分的取舍,我們打算控制中心原有的功能對 Dubbo3 服務依然支持,如服務發現、同中心尋址、上下負載、服務測驗等操作和之前保持一致,而 Dubbo 特有的服務治理功能如動態配置、Mesh 路由,我們將新增功能對其支持,保證 Dubbo3 功能的完整,
總結
Dubbo 3 是一個優秀的微服務框架,提供的 SPI 以及 Extension 機制能夠非常方便的讓用戶去擴展實作想要功能,而且 Dubbo3 也更適應目前云原生的架構,Dubbo 3.1.x 版本支持 Sidecar 和 Proxyless 的 Mesh 方案,而且社區也在準備開源 Java Agent 方式的 Proxyless,這樣就能較好的將微服務架框的 Framework 與資料面解耦,降低微服務框架的維護成本和升級成本,我們也會和社區一起探索,共建 Dubbo 社區的繁榮,
搜索關注官方微信公眾號:Apache Dubbo,了解更多業界最新動態,掌握大廠面試必備 Dubbo 技能
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538914.html
標籤:Java
上一篇:Mybatis快取機制
