從編程開發(fā)的角度來說,Apache Dubbo (以下簡稱 Dubbo )首先是一款 RPC 服務(wù)框架,它最大的優(yōu)勢在于提供了面向接口代理的服務(wù)編程模型,對開發(fā)者屏蔽了底層的遠程通信細節(jié)。同時 Dubbo 也是一款服務(wù)治理框架,它為分布式部署的微服務(wù)提供了服務(wù)發(fā)現(xiàn)、流量調(diào)度等服務(wù)治理解決方案。
在這篇文章中,我們將以以上基礎(chǔ)能力為背景,嘗試突破 Dubbo 體系自身,探索如何利用 Dubbo 對多協(xié)議、多服務(wù)發(fā)現(xiàn)模型的支持,來實現(xiàn)異構(gòu)微服務(wù)體系間的互聯(lián)互通。在實際業(yè)務(wù)場景中,這可以用來解決異構(gòu)技術(shù)體系共存場景下的通信問題,幫助公司實現(xiàn)在異構(gòu)技術(shù)體系間作平滑遷移,解決大規(guī)??鐓^(qū)域、多集群部署場景的地址發(fā)現(xiàn)及流量調(diào)度等問題。
面向接口代理的透明服務(wù)開發(fā)框架
我們還是從 Dubbo 是一個微服務(wù)開發(fā)框架 這個大家熟知的概念開始。就像 Spring 是開發(fā) Java 應(yīng)用的基礎(chǔ)框架一樣,我們經(jīng)常會選用 Dubbo 作為開發(fā)微服務(wù)業(yè)的基礎(chǔ)框架。 Dubbo 框架的最大優(yōu)勢我認為就在其面向接口的編程模型,使得開發(fā)遠程服務(wù)調(diào)用就像開發(fā)本地服務(wù)一樣(以 Java 語言為例):
服務(wù)定義
public?interface?GreetingsService?{ ????String?sayHi(String?name); }
消費方調(diào)用服務(wù)
//?和調(diào)用本地服務(wù)一樣,完全透明。 @Reference private?GreetingService?greetingService; public?void?doSayHello(String?name)?{ ??greetingService.sayHi("Hello?world!"); }
下圖是 Dubbo 的基本工作原理圖,服務(wù)提供者與服務(wù)消費者之間通過注冊中心協(xié)調(diào)地址,通過約定的協(xié)議實現(xiàn)數(shù)據(jù)交換。
同構(gòu)/異構(gòu)微服務(wù)體系面臨的問題
關(guān)于 Dubbo 協(xié)議本身及其服務(wù)治理相關(guān)功能細節(jié)并不是本文的重點,我們今天將從一個更高的層次,來看看公司內(nèi)部構(gòu)建微服務(wù)體系所面的挑戰(zhàn),以及 Dubbo 能為架構(gòu)選型和遷移等提供哪些解決思路。
一個公司內(nèi)部的微服務(wù)可能都是基于某一個相同的服務(wù)框架開發(fā)的,比如說 Dubbo,對于這樣的架構(gòu),我們稱之為是同構(gòu)的微服務(wù)體系;而有些公司的微服務(wù)可能是使用多個不同的服務(wù)框架所建設(shè),我們稱之為異構(gòu)的微服務(wù)體系,多個不同技術(shù)棧微服務(wù)體系的共存在大型組織內(nèi)還是非常普遍的,造成這種局面可能有很多原因。比如,可能是遺留系統(tǒng)帶來的,也可能是公司正在做技術(shù)棧遷移,或者就是不同業(yè)務(wù)部門為了滿足各自特殊需求而做的獨立選型(這也意味著異構(gòu)微服務(wù)體系的長期共存)。
1. 異構(gòu)微服務(wù)體系共存
我們很容易想到的一個挑戰(zhàn)是:不同的體系間通常是使用不同的 RPC 通信協(xié)議、部署獨立的注冊中心集群,面對這種多協(xié)議、多注冊中心集群的場景,要如何實現(xiàn)相互之間透明的地址發(fā)現(xiàn)和透明的 RPC 調(diào)用?如果我們什么都不做,那么每個微服務(wù)體系就只能感知到自己體系內(nèi)的服務(wù)狀態(tài),流量也在各自的體系內(nèi)封閉。而要做到從體系 A 平滑的遷移到體系 B,或者想長期的保持公司內(nèi)部多個體系的共存,則解決不同體系間的互聯(lián)互通,實現(xiàn)流量的透明調(diào)度將是非常重要的環(huán)節(jié)。
2. Dubbo 體系內(nèi)部
多協(xié)議、多注冊中心集群的問題在同構(gòu)的微服務(wù)體系中也可能存在,尤其是當(dāng)一個組織內(nèi)部的微服務(wù)規(guī)模增長到一定量級的時候。
我們可能要在不同的服務(wù)之間采用不同的通信協(xié)議,因為不同的服務(wù)面臨不同的業(yè)務(wù)場景,而這也進一步導(dǎo)致了數(shù)據(jù)傳輸特點的不同,我們需要分別采用更適合各類業(yè)務(wù)特點的協(xié)議。比如典型的場景:我們可能對于普通的業(yè)務(wù)服務(wù)采用 Dubbo 協(xié)議,對于和 FrontEnd 交互的服務(wù)需要 HTTP 協(xié)議,而對于需要流式數(shù)據(jù)傳輸?shù)臉I(yè)務(wù)則采用 gRPC 協(xié)議等等。
Dubbo 體系內(nèi)部另一個常出現(xiàn)的問題是,在大規(guī)模分布式部署的場景下,微服務(wù)系統(tǒng)會做跨區(qū)域、跨注冊中心的部署,這個時候就會出現(xiàn)多集群間地址同步和流量調(diào)度的問題。
總結(jié)起來,不論是同構(gòu)體系還是異構(gòu)體系,都面臨對多協(xié)議通信、多注冊中心集群地址發(fā)現(xiàn)的問題。Dubbo 目前是支持多協(xié)議、多注冊中心的,可以說就是為解決我們上面分析的 Dubbo 同構(gòu)體系內(nèi)的場景而設(shè)計的,因此下面我們從同構(gòu)體系的多協(xié)議、多注冊中心場景講起,先了解 Dubbo 多協(xié)議、多注冊中心的基本支持情況以及它們是如何工作的。而在后面的一章再進一步探索怎么擴展這個能力來支持異構(gòu)微服務(wù)體系的互聯(lián)互通。
Dubbo 體系內(nèi)的多協(xié)議、多注冊中心機制
我們將通過兩個場景示例,來分別具體的講一下 Dubbo 的多協(xié)議、多注冊中心機制的使用方式和工作原理。
多協(xié)議
以上是使用 Dubbo 開發(fā)的一套微服務(wù),服務(wù)間通信使用到了不同的協(xié)議,根據(jù)我們的調(diào)研發(fā)現(xiàn),公司內(nèi)部啟用多協(xié)議其實是非常普遍需求,具體場景在此我們暫不做解釋。
應(yīng)用 B 作為服務(wù)提供者,發(fā)布了 5 個服務(wù),其中:
DemoService1 DemoService2 通過 dubbo 協(xié)議發(fā)布
DemoService3 DemoService4 通過 gRPC 協(xié)議發(fā)布
DemoService0 通過 dubbo 、gRPC 雙協(xié)議發(fā)布
應(yīng)用 A 作為消費者,使用 dubbo 協(xié)議消費 DemoService1 DemoService2,使用 gRPC 協(xié)議消費 DemoService0。
應(yīng)用 B 作為消費者,使用 gRPC 協(xié)議消費 DemoService2 DemoService4,使用 dubbo 協(xié)議消費 DemoService0。
以下是具體的代碼配置:
提供端應(yīng)用 B
消費端應(yīng)用 A
消費端應(yīng)用 C
Dubbo 多協(xié)議支持現(xiàn)狀
Dubbo 目前所支持的協(xié)議包括 Dubbo、REST、Thrift、gRPC、JsonRPC、Hessian 等,基本涵蓋了業(yè)界大多數(shù)主流的 RPC 通信協(xié)議。需要注意的是,這些協(xié)議的支持都是以直接集成官方 Release 實現(xiàn)的形式來做的,我認為這是一個很好的選擇,既保證了協(xié)議解析自身的穩(wěn)定性,又能使 Dubbo 社區(qū)更專注的將更多的精力放在 Dubbo 外圍服務(wù)治理能力的改善上。試想如果 Dubbo 社區(qū)自己為每個協(xié)議提供實現(xiàn),那是要花費多少精力和時間才能使每種協(xié)議達到穩(wěn)定的生產(chǎn)可用。
除了以上官方提供支持的協(xié)議之外,得益于 Dubbo 靈活的擴展機制,想要為 Dubbo 擴展協(xié)議非常容易,開發(fā)者可以隨時為 Dubbo 增加更多的協(xié)議支持,包括自有協(xié)議擴展。
關(guān)于對 gRPC (HTTP/2) 協(xié)議的支持,請參閱《Dubbo 在跨語言和協(xié)議穿透性方向的探索:支持 HTTP/2 gRPC》。
多協(xié)議能解決的問題
將 RPC 框架無縫地接入 Dubbo 的服務(wù)治理體系。
通過協(xié)議擴展將 RPC 協(xié)議納入 Dubbo 服務(wù)開發(fā)體系,從而復(fù)用 Dubbo 的編程模型和服務(wù)發(fā)現(xiàn)、流量管控等能力。比如 gRPC,其服務(wù)治理體系相對比較弱、編程 API 不夠友好,很難直接用于微服務(wù)開發(fā)。
滿足不同場景的調(diào)用需求。
各個服務(wù)可能是為了滿足不同業(yè)務(wù)需求而開發(fā),同時外圍消費端應(yīng)用的技術(shù)棧也可能多種多樣,通過啟用不同的通信協(xié)議,可以最優(yōu)化不同場景的通信需求。
實現(xiàn)協(xié)議間的遷移。
通過支持多種協(xié)議,借助注冊中心的協(xié)調(diào),可以快速滿足公司內(nèi)協(xié)議遷移的需求。如從自有協(xié)議升級到 Dubbo 協(xié)議,Dubbo 協(xié)議自身升級,從 Dubbo 協(xié)議遷移到 gRPC,從 REST 遷移到 Dubbo 協(xié)議等。
多注冊中心
當(dāng)服務(wù)集群規(guī)模小的時候,一個中心化的集群部署方案能很好的解決我們的業(yè)務(wù)問題。但是隨著應(yīng)用規(guī)模的增長、用戶流量的增加,我們就不得不考慮要為業(yè)務(wù)系統(tǒng)引入跨區(qū)域、多集群的部署方案,而此時同業(yè)務(wù)系統(tǒng)密切相關(guān)的注冊中心集群也面臨部署方案的選型:
繼續(xù)維持全局共享的注冊中心集群。這種架構(gòu)方案的優(yōu)點是簡單;缺點是注冊中心集群由于要保存全量的地址數(shù)據(jù),存儲和推送壓力會變得很大,另外對于一些注冊中心產(chǎn)品(如 Zookeeper 等)在跨集群網(wǎng)絡(luò)部署的場景下穩(wěn)定性和性能可能都會面臨挑戰(zhàn)。
每個業(yè)務(wù)集群部署獨立的注冊中心集群。多注冊中心集群的優(yōu)點是能解決跨集群網(wǎng)絡(luò)可用性的問題,同時也能夠減輕注冊中心的存儲和推送壓力;缺點則是要求服務(wù)框架(如 Dubbo 等)能有同時發(fā)布/監(jiān)聽多個注冊中心集群的能力。
下面我們具體看一下,Dubbo 為多注冊中心集群場景提供的解決方案。
上圖有兩個業(yè)務(wù)集群,分別部署在北京和上海,每個業(yè)務(wù)集群有自己獨立的注冊中心集群,要解決兩個業(yè)務(wù)集群間服務(wù)的透明 RPC 通信問題。
服務(wù)提供端,雙注冊中心發(fā)布
服務(wù)消費端,根據(jù)消費需求做單/雙注冊中心訂閱
Dubbo 對異構(gòu)注冊中心集群的支持
雖然我們會做多注冊中心集群部署,但通常情況下,我們部署的都是相同的注冊中心產(chǎn)品,如都是 Zookeeper、Nacos;而對于注冊中心遷移的場景,則要求 Dubbo 能提供對更多的注冊中心產(chǎn)品的支持,或者最重要的要有很好的擴展能力。Dubbo 官方目前支持的注冊中心實現(xiàn)有:
這里需要特別提到的一點是,當(dāng)前 Dubbo 的服務(wù)注冊/發(fā)現(xiàn)模型是以接口為粒度的,而從 2.7.5 版本開始,Dubbo 新引入了應(yīng)用粒度的服務(wù)注冊/發(fā)現(xiàn)模型。這一方面有助于優(yōu)化 Dubbo 當(dāng)前服務(wù)發(fā)現(xiàn)機制、提升服務(wù)容量,另一方面對于聯(lián)通以 SpringCloud 為代表的微服務(wù)體系也非常重要(關(guān)于這點在下一章中有進一步提及)。更多關(guān)于《應(yīng)用粒度服務(wù)發(fā)現(xiàn):服務(wù)自省》的介紹,我們將在接下來的文章或文檔中予以補充,請持續(xù)關(guān)注。
多訂閱帶來的流量調(diào)度問題
在引入多注冊中心集群后,Dubbo 在流量選址時的多了一層注冊中心集群間的負載均衡:
在 Cluster Invoker 這一級,我們支持的選址策略有(2.7.5+ 版本,具體使用請參見文檔):
指定優(yōu)先級
同 zone 優(yōu)先
權(quán)重輪詢
默認,stick to 任意可用
多注冊中心適用的場景
同區(qū)域流量優(yōu)先調(diào)度
出于容災(zāi)或者服務(wù)伸縮性需求,服務(wù)/應(yīng)用往往需要部署在多個獨立的機房/區(qū)域,在每個區(qū)域有獨立注冊中心集群的場景下,實現(xiàn)同區(qū)域的流量優(yōu)先調(diào)度就能很好的解決延遲和可用性問題。
注冊中心遷移
公司的服務(wù)一直以來可能是存儲在某一個注冊中心,如 Zookeeper,但到了某個時間節(jié)點,因為各種各樣的原因,當(dāng)我們要遷移到另外的注冊中心時,多注冊中心模型能夠保證平滑的遷移。
異構(gòu)系統(tǒng)互通
不同微服務(wù)體系開發(fā)的服務(wù),都封閉在各自的服務(wù)發(fā)現(xiàn)體系中,而通過統(tǒng)一的多注冊中心模型,可以實現(xiàn)不同體系的服務(wù)互相發(fā)現(xiàn)。
借助 Dubbo 聯(lián)通異構(gòu)的微服務(wù)體系
上文我們提到了在組織內(nèi)存在異構(gòu)微服務(wù)體系的各種合理可能性,現(xiàn)在我們來具體看一下異構(gòu)微服務(wù)體系的實際場景,以及使用 Dubbo 實現(xiàn)互聯(lián)互通的解決方法。首先我們先通過一張圖來看一下,聯(lián)通異構(gòu)的微服務(wù)體系具體是一個什么樣的場景。
如上圖所示,我們有部分微服務(wù)可以是基于 SpringCloud、gRPC、K8S 或者是自建體系構(gòu)建的,他們各自之間默認是相互隔離無法聯(lián)通的。當(dāng)我們再構(gòu)建一套基于 Dubbo 的微服務(wù)體系時,則利用 Dubbo 的多協(xié)議、多服務(wù)發(fā)現(xiàn)模型,我們就可以做到和各個微服務(wù)體系間的兩兩之間的互聯(lián)互通。進一步的,如圖中橙色箭頭所示,依賴 Dubbo 體系作為橋接層,我們還可以實現(xiàn)兩個異構(gòu)微服務(wù)體系間的打通。
對于以下幾個示例場景,由于在地址發(fā)現(xiàn)層面目前沒有統(tǒng)一的標(biāo)準(zhǔn),我們暫且假設(shè)地址發(fā)現(xiàn)層面不同的體系建是沒有障礙的,我們將重點關(guān)注遷移的基本流程以及通信協(xié)議環(huán)節(jié)。(關(guān)于地址發(fā)現(xiàn)部分,我們將在后續(xù)《服務(wù)自?。夯趹?yīng)用粒度的服務(wù)發(fā)現(xiàn)》之后再深入探討)
Dubbo 體系內(nèi)的協(xié)議遷移(共存)
絕大多數(shù)開發(fā)者對 Dubbo 有這么一個固有認知:使用 Dubbo 開發(fā)微服務(wù)系統(tǒng),則就要用 Dubbo 協(xié)議來作為服務(wù)間的通信協(xié)議才是最優(yōu)方案。實際上,我們完全沒有必要只束縛在 Dubbo RPC 協(xié)議上。Dubbo 作為微服務(wù)開發(fā)框架和 Dubbo 作為 RPC 協(xié)議這是兩個概念,其實是完全可以分開來看待的,比如我們用 Dubbo 框架開發(fā)的業(yè)務(wù)系統(tǒng),選用 rest、gRPC 通信是完全沒有問題的(參加 Dubbo 支持的協(xié)議列表),具體用什么協(xié)議根據(jù)業(yè)務(wù)特點和技術(shù)規(guī)劃才是最適合的。
當(dāng)前在云原生、Mesh 的大背景下, HTTP1/2、gRPC 協(xié)議開始受到越來越多的關(guān)注,一方面原因自然是因為它們在標(biāo)準(zhǔn)化方面做的更好,得到的更多的網(wǎng)絡(luò)設(shè)備和基礎(chǔ)設(shè)施的支持,具備更好的通用性和穿透性。對于很多有云原生遷移意愿的企業(yè)來說,往此類協(xié)議遷移無疑將對之后的架構(gòu)升級有更多的幫助。
下圖演示了在 Dubbo 體系內(nèi),從 Dubbo 協(xié)議向 gRPC 協(xié)議遷移的一個中間狀態(tài)。
最左邊的代表尚未遷移的老應(yīng)用,這類應(yīng)用在遷移過程中仍然要消費和提供 Dubbo 協(xié)議的服務(wù)。
中間的代表處于遷移中的應(yīng)用,他們中間可能有些是服務(wù)提供者,既要為左邊的老系統(tǒng)提供提供 Dubbo 協(xié)議服務(wù);又要為右邊的新系統(tǒng)提供 gRPC 服務(wù);因此他們都是雙協(xié)議暴露服務(wù)。
最右邊則代表是新開發(fā)的或者已經(jīng)遷移完成的應(yīng)用,這個體系內(nèi)已能完全用 gRPC 協(xié)議通信。
最終度過中間態(tài)后,我們期望所有的應(yīng)用都達到最左邊應(yīng)用的狀態(tài),實現(xiàn)完全的 gRPC 協(xié)議通信。
Spring Cloud 體系遷移到 Dubbo 體系(共存)
如前文所述,由于 SpringCloud 和 Dubbo 間服務(wù)發(fā)現(xiàn)模型的問題,要兩個體系間的地址互通需要 Dubbo 側(cè)作相應(yīng)的適配,關(guān)于這部分內(nèi)容將在接下來的 2.7.5 版本《服務(wù)自省》部分發(fā)布,在此我們暫且認為已經(jīng)打通。
Dubbo 體系內(nèi)的部分應(yīng)用作為透明的聯(lián)通兩個體系的關(guān)鍵節(jié)點,部分服務(wù)提供者應(yīng)用要雙協(xié)議發(fā)布、部分消費者應(yīng)用要做到選定協(xié)議消費。由于老的 Spring Cloud 體系不允許做任何改動,因此聯(lián)通兩套體系的關(guān)鍵是 REST 協(xié)議,對 Dubbo 側(cè)的應(yīng)用來說:
部分應(yīng)用可能要以 REST 協(xié)議消費 SpringCloud 的服務(wù);
部分應(yīng)用可能要暴露 REST 協(xié)議共 SpringCloud 消費;
Dubbo 自有體系內(nèi)則通過自己選定的協(xié)議通信,這里就比較靈活了,可以是 Dubbo、REST、gRPC 等其中的任一種。而如果選定 REST 協(xié)議則對于與 SpringCloud 體系的聯(lián)通就變得更加自然了,因為兩端的協(xié)議都是統(tǒng)一的。
對于消費 Spring Cloud 服務(wù)的應(yīng)用,要配置服務(wù) :
對于提供服務(wù)給 Spring Cloud 側(cè)消費的應(yīng)用,則指定服務(wù)暴露為 rest 協(xié)議,或者雙協(xié)議暴露(因如果這個服務(wù)還要被新體系內(nèi)的應(yīng)用調(diào)用到):
作為 Dubbo 的維護者,雖然我們這里有明顯的偏向性,講的是從如何從 SpringCloud 體系遷移到 Dubbo 體系。但是反過來考慮,如果你已經(jīng)或者即將選型 Dubbo 來開發(fā)微服務(wù),則未來從 Dubbo 遷移到 SpringCloud 也是同樣的思路,Dubbo 的多協(xié)議、多注冊模型為雙向遷移都提供了同樣的靈活性。
評論