您好,登錄后才能下訂單哦!
作者 | 劉軍(陸龜) Apache Dubbo PMC
概述
社區(qū)版本 Dubbo 從 2.7.5 版本開始,新引入了一種基于實(shí)例(應(yīng)用)粒度的服務(wù)發(fā)現(xiàn)機(jī)制,這是我們?yōu)?Dubbo 適配云原生基礎(chǔ)設(shè)施的一步重要探索。版本發(fā)布到現(xiàn)在已有近半年時(shí)間,經(jīng)過這段時(shí)間的探索與總結(jié),我們對(duì)這套機(jī)制的可行性與穩(wěn)定性有了更全面、深入的認(rèn)識(shí);同時(shí)在 Dubbo 3.0 的規(guī)劃也在全面進(jìn)行中,如何讓應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)成為未來下一代服務(wù)框架 Dubbo 3.0 的基礎(chǔ)服務(wù)模型,解決云原生、規(guī)模化微服務(wù)集群擴(kuò)容與可伸縮性問題,也已經(jīng)成為我們當(dāng)前工作的重點(diǎn)。
既然這套新機(jī)制如此重要,那它到底是怎么工作的呢?今天我們就來詳細(xì)解讀一下。在最開始的社區(qū)版本,我們給這個(gè)機(jī)制取了一個(gè)神秘的名字 - 服務(wù)自省,下文將進(jìn)一步解釋這個(gè)名字的由來,并引用服務(wù)自省代指這套應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)機(jī)制。
熟悉 Dubbo 開發(fā)者應(yīng)該都知道,一直以來都是面向 RPC 方法去定義服務(wù)的,并且這也是 Dubbo 開發(fā)友好性、治理功能強(qiáng)的基礎(chǔ)。既然如此,那我們?yōu)槭裁催€要定義個(gè)應(yīng)用粒度的服務(wù)發(fā)現(xiàn)機(jī)制呢?這個(gè)機(jī)制到底是怎么工作的?它與當(dāng)前機(jī)制的區(qū)別是什么?它能給我們帶來哪些好處那?對(duì)適配云原生、性能提升又有哪些幫助?
帶著所有的這些問題,我們開始本文的講解。
服務(wù)自省是什么?
首先,我們先來解釋文章開篇提到的問題:
應(yīng)用粒度服務(wù)發(fā)現(xiàn)是到底是一種怎樣的模型,它與當(dāng)前的 Dubbo 服務(wù)發(fā)現(xiàn)模型的區(qū)別是什么?
我們?yōu)槭裁唇兴?wù)自省?
所謂“應(yīng)用/實(shí)例粒度” 或者“RPC 服務(wù)粒度”強(qiáng)調(diào)的是一種地址發(fā)現(xiàn)的數(shù)據(jù)組織格式。
以 Dubbo 當(dāng)前的地址發(fā)現(xiàn)數(shù)據(jù)格式為例,它是“RPC 服務(wù)粒度”的,它是以 RPC 服務(wù)作為 key,以實(shí)例列表作為 value 來組織數(shù)據(jù)的:
"RPC Service1": [
{"name":"instance1", "ip":"127.0.0.1", "metadata":{"timeout":1000}},
{"name":"instance2", "ip":"127.0.0.1", "metadata":{"timeout":2000}},
{"name":"instance3", "ip":"127.0.0.1", "metadata":{"timeout":3000}},
]
"RPC Service2": [Instance list of RPC Service2],
"RPC ServiceN": [Instance list of RPC ServiceN]
而我們新引入的“應(yīng)用粒度的服務(wù)發(fā)現(xiàn)”,它以應(yīng)用名(Application)作為 key,以這個(gè)應(yīng)用部署的一組實(shí)例(Instance)列表作為 value。這帶來兩點(diǎn)不同:
數(shù)據(jù)映射關(guān)系變了,從 RPC Service -> Instance 變?yōu)?Application -> Instance;
數(shù)據(jù)變少了,注冊(cè)中心沒有了 RPC Service 及其相關(guān)配置信息。
"application1": [
{"name":"instance1", "ip":"127.0.0.1", "metadata":{}},
{"name":"instance2", "ip":"127.0.0.1", "metadata":{}},
{"name":"instanceN", "ip":"127.0.0.1", "metadata":{}}
]
要進(jìn)一步理解新模型帶來的變化,我們看一下應(yīng)用與 RPC 服務(wù)間的關(guān)系,顯而易見的,1 個(gè)應(yīng)用內(nèi)可能會(huì)定義 n 個(gè) RPC Service。因此 Dubbo 之前的服務(wù)發(fā)現(xiàn)粒度更細(xì),在注冊(cè)中心產(chǎn)生的數(shù)據(jù)條目也會(huì)更多(與 RPC 服務(wù)成正比),同時(shí)也存在一定的數(shù)據(jù)冗余。
簡單理解了應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)的基本機(jī)制,接著解釋它為什么會(huì)被叫做“服務(wù)自省”?
其實(shí)這還是得從它的工作原理說起,上面我們提到,應(yīng)用粒度服務(wù)發(fā)現(xiàn)的數(shù)據(jù)模型有幾個(gè)以下明顯變化:數(shù)據(jù)中心的數(shù)據(jù)量少了,RPC 服務(wù)相關(guān)的數(shù)據(jù)在注冊(cè)中心沒有了,現(xiàn)在只有 application - instance 這兩個(gè)層級(jí)的數(shù)據(jù)。為了保證這部分缺少的 RPC 服務(wù)數(shù)據(jù)仍然能被 Consumer 端正確的感知,我們?cè)?Consumer 和 Provider 間建立了一條單獨(dú)的通信通道:Consumer 和 Provider 兩兩之間通過特定端口交換信息,我們把這種 Provider 自己主動(dòng)暴露自身信息的行為認(rèn)為是一種內(nèi)省機(jī)制,因此從這個(gè)角度出發(fā),我們把整個(gè)機(jī)制命名為:服務(wù)自省。
為什么需要服務(wù)自???
上面講服務(wù)自省的大概原理的時(shí)候也提到了它給注冊(cè)中心帶來的幾點(diǎn)不同,這幾點(diǎn)不同體現(xiàn)在 Dubbo 框架側(cè)(甚至整個(gè)微服務(wù)體系中),有以下優(yōu)勢(shì):
與業(yè)界主流微服務(wù)模型對(duì)齊,比如 SpringCloud、Kubernetes Native Service 等;
提升性能與可伸縮性。注冊(cè)中心數(shù)據(jù)的重新組織(減少),能最大幅度的減輕注冊(cè)中心的存儲(chǔ)、推送壓力,進(jìn)而減少 Dubbo Consumer 側(cè)的地址計(jì)算壓力;集群規(guī)模也開始變得可預(yù)測、可評(píng)估(與 RPC 接口數(shù)量無關(guān),只與實(shí)例部署規(guī)模相關(guān))。
自動(dòng)、透明的實(shí)例地址發(fā)現(xiàn)(負(fù)載均衡)是所有微服務(wù)框架需要解決的事情,這能讓后端的部署結(jié)構(gòu)對(duì)上游微服務(wù)透明,上游服務(wù)只需要從收到的地址列表中選取一個(gè),發(fā)起調(diào)用就可以了。要實(shí)現(xiàn)以上目標(biāo),涉及兩個(gè)關(guān)鍵點(diǎn)的自動(dòng)同步:
實(shí)例地址,服務(wù)消費(fèi)方需要知道地址以建立鏈接;
RPC 方法定義,服務(wù)消費(fèi)方需要知道 RPC 服務(wù)的具體定義,不論服務(wù)類型是 rest 或 rmi 等。
對(duì)于 RPC 實(shí)例間借助注冊(cè)中心的數(shù)據(jù)同步,REST 定義了一套非常有意思的成熟度模型,感興趣的朋友可以參考這里的鏈接 :
https://www.martinfowler.com/articles/richardsonMaturityModel.html
按照文章中的 4 級(jí)成熟度定義,Dubbo 當(dāng)前基于接口粒度的模型可以對(duì)應(yīng)到 L4 級(jí)別。
接下來,我們看看 Dubbo、SpringCloud 以及 Kubernetes 分別是怎么圍繞自動(dòng)化的實(shí)例地址發(fā)現(xiàn)這個(gè)目標(biāo)設(shè)計(jì)的。
Spring Cloud 通過注冊(cè)中心只同步了應(yīng)用與實(shí)例地址,消費(fèi)方可以基于實(shí)例地址與服務(wù)提供方建立鏈接,但是消費(fèi)方對(duì)于如何發(fā)起 HTTP 調(diào)用(SpringCloud 基于 rest 通信)一無所知,比如對(duì)方有哪些 HTTP endpoint,需要傳入哪些參數(shù)等。
RPC 服務(wù)這部分信息目前都是通過線下約定或離線的管理系統(tǒng)來協(xié)商的。這種架構(gòu)的優(yōu)缺點(diǎn)總結(jié)如下:
優(yōu)勢(shì):部署結(jié)構(gòu)清晰、地址推送量??;
缺點(diǎn):地址訂閱需要指定應(yīng)用名, provider 應(yīng)用變更(拆分)需消費(fèi)端感知;RPC 調(diào)用無法全自動(dòng)同步。
Dubbo 通過注冊(cè)中心同時(shí)同步了實(shí)例地址和 RPC 方法,因此其能實(shí)現(xiàn) RPC 過程的自動(dòng)同步,面向 RPC 編程、面向 RPC 治理,對(duì)后端應(yīng)用的拆分消費(fèi)端無感知,其缺點(diǎn)則是地址推送數(shù)量變大,和 RPC 方法成正比。
Dubbo 要支持 Kubernetes native service,相比之前自建注冊(cè)中心的服務(wù)發(fā)現(xiàn)體系來說,在工作機(jī)制上主要有兩點(diǎn)變化:
服務(wù)注冊(cè)由平臺(tái)接管,provider 不再需要關(guān)心服務(wù)注冊(cè);
consumer 端服務(wù)發(fā)現(xiàn)將是 Dubbo 關(guān)注的重點(diǎn),通過對(duì)接平臺(tái)層的 API-Server、DNS 等,Dubbo client 可以通過一個(gè) Service Name(通常對(duì)應(yīng)到 Application Name)查詢到一組 Endpoints(一組運(yùn)行 provider 的 pod),通過將 Endpoints 映射到 Dubbo 內(nèi)部地址列表,以驅(qū)動(dòng) Dubbo 內(nèi)置的負(fù)載均衡機(jī)制工作。
Kubernetes Service 作為一個(gè)抽象概念,怎么映射到 Dubbo 是一個(gè)值得討論的點(diǎn)
Service Name - > Application Name,Dubbo 應(yīng)用和 Kubernetes 服務(wù)一一對(duì)應(yīng),對(duì)于微服務(wù)運(yùn)維和建設(shè)環(huán)節(jié)透明,與開發(fā)階段解耦。
apiVersion: v1
kind: Service
metadata:
name: provider-app-name
spec:
selector:
app: provider-app-name
ports:
- protocol: TCP
port:
targetPort: 9376
Service Name - > Dubbo RPC Service,Kubernetes 要維護(hù)調(diào)度的服務(wù)與應(yīng)用內(nèi)建 RPC 服務(wù)綁定,維護(hù)的服務(wù)數(shù)量變多。
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-1
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-2
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-N
spec:
selector:
app: provider-app-name
ports: ##
...
結(jié)合以上幾種不同微服務(wù)框架模型的分析,我們可以發(fā)現(xiàn),Dubbo 與 SpringCloud、Kubernetes 等不同產(chǎn)品在微服務(wù)的抽象定義上還是存在很大不同的。SpringCloud 和 Kubernetes 在微服務(wù)的模型抽象上還是比較接近的,兩者基本都只關(guān)心實(shí)例地址的同步,如果我們?nèi)リP(guān)心其他的一些服務(wù)框架產(chǎn)品,會(huì)發(fā)現(xiàn)它們絕大多數(shù)也是這么設(shè)計(jì)的;
即 REST 成熟度模型中的 L3 級(jí)別。
對(duì)比起來 Dubbo 則相對(duì)是比較特殊的存在,更多的是從 RPC 服務(wù)的粒度去設(shè)計(jì)的。
對(duì)應(yīng) REST 成熟度模型中的 L4 級(jí)別。
如我們上面針對(duì)每種模型做了詳細(xì)的分析,每種模型都有其優(yōu)勢(shì)和不足。而我們最初決定 Dubbo 要做出改變,往其他的微服務(wù)發(fā)現(xiàn)模型上的對(duì)齊,是我們最早在確定 Dubbo 的云原生方案時(shí),我們發(fā)現(xiàn)要讓 Dubbo 去支持 Kubernetes Native Service,模型對(duì)齊是一個(gè)基礎(chǔ)條件;另一點(diǎn)是來自用戶側(cè)對(duì) Dubbo 場景化的一些工程實(shí)踐的需求,得益于 Dubbo 對(duì)多注冊(cè)、多協(xié)議能力的支持,使得 Dubbo 聯(lián)通不同的微服務(wù)體系成為可能,而服務(wù)發(fā)現(xiàn)模型的不一致成為其中的一個(gè)障礙,這部分的場景描述請(qǐng)參見這里。
這部分涉及到和注冊(cè)中心、配置中心的交互,關(guān)于不同模型下注冊(cè)中心數(shù)據(jù)的變化,之前原理部分我們簡單分析過。為更直觀的對(duì)比服務(wù)模型變更帶來的推送效率提升,我們來通過一個(gè)示例看一下不同模型注冊(cè)中心的對(duì)比:
圖中左邊是微服務(wù)框架的一個(gè)典型工作流程,Provider 和 Consumer 通過注冊(cè)中心實(shí)現(xiàn)自動(dòng)化的地址通知。其中,Provider 實(shí)例的信息如圖中表格所示:
應(yīng)用 DEMO 包含三個(gè)接口 DemoService 1 2 3,當(dāng)前實(shí)例的 ip 地址為 10.210.134.30。
對(duì)于 Spring Cloud 和 Kubernetes 模型,注冊(cè)中心只會(huì)存儲(chǔ)一條 DEMO - 10.210.134.30+metadata 的數(shù)據(jù);
對(duì)于老的 Dubbo 模型,注冊(cè)中心存儲(chǔ)了三條接口粒度的數(shù)據(jù),分別對(duì)應(yīng)三個(gè)接口 DemoService 1 2 3,并且很多的址數(shù)據(jù)都是重復(fù)的。
可以總結(jié)出,基于應(yīng)用粒度的模型所存儲(chǔ)和推送的數(shù)據(jù)量是和應(yīng)用、實(shí)例數(shù)成正比的,只有當(dāng)我們的應(yīng)用數(shù)增多或應(yīng)用的實(shí)例數(shù)增長時(shí),地址推送壓力才會(huì)上漲。
而對(duì)于基于接口粒度的模型,數(shù)據(jù)量是和接口數(shù)量正相關(guān)的,鑒于一個(gè)應(yīng)用通常發(fā)布多個(gè)接口的現(xiàn)狀,這個(gè)數(shù)量級(jí)本身比應(yīng)用粒度是要乘以倍數(shù)的;另外一個(gè)關(guān)鍵點(diǎn)在于,接口粒度導(dǎo)致的集群規(guī)模評(píng)估的不透明,相對(duì)于實(shí)i例、應(yīng)用增長都通常是在運(yùn)維側(cè)的規(guī)劃之中,接口的定義更多的是業(yè)務(wù)側(cè)的內(nèi)部行為,往往可以繞過評(píng)估給集群帶來壓力。
以 Consumer 端服務(wù)訂閱舉例,根據(jù)我對(duì)社區(qū)部分 Dubbo 中大規(guī)模頭部用戶的粗略統(tǒng)計(jì),根據(jù)受統(tǒng)計(jì)公司的實(shí)際場景,一個(gè) Consumer 應(yīng)用要消費(fèi)(訂閱)的 Provier 應(yīng)用數(shù)量往往要超過 10 個(gè),而具體到其要消費(fèi)(訂閱)的的接口數(shù)量則通常要達(dá)到 30 個(gè),平均情況下 Consumer 訂閱的 3 個(gè)接口來自同一個(gè) Provider 應(yīng)用,如此計(jì)算下來,如果以應(yīng)用粒度為地址通知和選址基本單位,則平均地址推送和計(jì)算量將下降 60% 還要多。
而在極端情況下,也就是當(dāng) Consumer 端消費(fèi)的接口更多的來自同一個(gè)應(yīng)用時(shí),這個(gè)地址推送與內(nèi)存消耗的占用將會(huì)進(jìn)一步得到降低,甚至可以超過 80% 以上。
一個(gè)典型的幾段場景即是 Dubbo 體系中的網(wǎng)關(guān)型應(yīng)用,有些網(wǎng)關(guān)應(yīng)用消費(fèi)(訂閱)達(dá) 100+ 應(yīng)用,而消費(fèi)(訂閱)的服務(wù)有 1000+ ,平均有 10 個(gè)接口來自同一個(gè)應(yīng)用,如果我們把地址推送和計(jì)算的粒度改為應(yīng)用,則地址推送量從原來的 n 1000 變?yōu)?n 100,地址數(shù)量降低可達(dá)近 90%。
工作原理
上面一節(jié)我們從服務(wù)模型及支撐大規(guī)模集群的角度分別給出了 Dubbo 往應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)靠攏的好處或原因,但這么做的同時(shí)接口粒度的服務(wù)治理能力還是要繼續(xù)保留,這是 Dubbo 框架編程模型易用性、服務(wù)治理能力優(yōu)勢(shì)的基礎(chǔ)。
以下是我認(rèn)為我們做服務(wù)模型遷移仍要堅(jiān)持的設(shè)計(jì)原則:
新的服務(wù)發(fā)現(xiàn)模型要實(shí)現(xiàn)對(duì)原有 Dubbo 消費(fèi)端開發(fā)者的無感知遷移,即 Dubbo 繼續(xù)面向 RPC 服務(wù)編程、面向 RPC 服務(wù)治理,做到對(duì)用戶側(cè)完全無感知;
建立 Consumer 與 Provider 間的自動(dòng)化 RPC 服務(wù)元數(shù)據(jù)協(xié)調(diào)機(jī)制,解決傳統(tǒng)微服務(wù)模型無法同步 RPC 級(jí)接口配置的缺點(diǎn)。
應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)作為一種新的服務(wù)發(fā)現(xiàn)機(jī)制,和以前 Dubbo 基于 RPC 服務(wù)粒度的服務(wù)發(fā)現(xiàn)在核心流程上基本上是一致的:即服務(wù)提供者往注冊(cè)中心注冊(cè)地址信息,服務(wù)消費(fèi)者從注冊(cè)中心拉取&訂閱地址信息。
這里主要的不同有以下兩點(diǎn):
注冊(cè)中心數(shù)據(jù)以“應(yīng)用 - 實(shí)例列表”格式組織,不再包含 RPC 服務(wù)信息;
以下是每個(gè) Instance metadata 的示例數(shù)據(jù),總的原則是 metadata 只包含當(dāng)前 instance 節(jié)點(diǎn)相關(guān)的信息,不涉及 RPC 服務(wù)粒度的信息。
總體信息概括如下:實(shí)例地址、實(shí)例各種環(huán)境標(biāo)、metadata service 元數(shù)據(jù)、其他少量必要屬性。
{
"name": "provider-app-name",
"id": "192.168.0.102:20880",
"address": "192.168.0.102",
"port": 20880,
"sslPort": null,
"payload": {
"id": null,
"name": "provider-app-name",
"metadata": {
"metadataService": "{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}",
"endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"storage-type": "local",
"revision": "6785535733750099598",
}
},
"registrationTimeUTC": 1583461240877,
"serviceType": "DYNAMIC",
"uriSpec": null
}
Client – Server 自行協(xié)商 RPC 方法信息。
在注冊(cè)中心不再同步 RPC 服務(wù)信息后,服務(wù)自省在服務(wù)消費(fèi)端和提供端之間建立了一條內(nèi)置的 RPC 服務(wù)信息協(xié)商機(jī)制,這也是“服務(wù)自省”這個(gè)名字的由來。服務(wù)端實(shí)例會(huì)暴露一個(gè)預(yù)定義的 MetadataService RPC 服務(wù),消費(fèi)端通過調(diào)用 MetadataService 獲取每個(gè)實(shí)例 RPC 方法相關(guān)的配置信息。
當(dāng)前 MetadataService 返回的數(shù)據(jù)格式如下:
[
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314"
]
熟悉 Dubbo 基于 RPC 服務(wù)粒度的服務(wù)發(fā)現(xiàn)模型的開發(fā)者應(yīng)該能看出來,服務(wù)自省機(jī)制機(jī)制將以前注冊(cè)中心傳遞的 URL 一拆為二:
一部分和實(shí)例相關(guān)的數(shù)據(jù)繼續(xù)保留在注冊(cè)中心,如 ip、port、機(jī)器標(biāo)識(shí)等;
另一部分和 RPC 方法相關(guān)的數(shù)據(jù)從注冊(cè)中心移除,轉(zhuǎn)而通過 MetadataService 暴露給消費(fèi)端。
理想情況下是能達(dá)到數(shù)據(jù)按照實(shí)例、RPC 服務(wù)嚴(yán)格區(qū)分開來,但明顯可以看到以上實(shí)現(xiàn)版本還存在一些數(shù)據(jù)冗余,有些也數(shù)據(jù)還未合理劃分。尤其是 MetadataService 部分,其返回的數(shù)據(jù)還只是簡單的 URL 列表組裝,這些 URL其實(shí)是包含了全量的數(shù)據(jù)。
以下是服務(wù)自省的一個(gè)完整工作流程圖,詳細(xì)描述了服務(wù)注冊(cè)、服務(wù)發(fā)現(xiàn)、MetadataService、RPC 調(diào)用間的協(xié)作流程。
服務(wù)提供者啟動(dòng),首先解析應(yīng)用定義的“普通服務(wù)”并依次注冊(cè)為 RPC 服務(wù),緊接著注冊(cè)內(nèi)建的 MetadataService 服務(wù),最后打開 TCP 監(jiān)聽端口;
啟動(dòng)完成后,將實(shí)例信息注冊(cè)到注冊(cè)中心(僅限 ip、port 等實(shí)例相關(guān)數(shù)據(jù)),提供者啟動(dòng)完成;
服務(wù)消費(fèi)者啟動(dòng),首先依據(jù)其要“消費(fèi)的 provider 應(yīng)用名”到注冊(cè)中心查詢地址列表,并完成訂閱(以實(shí)現(xiàn)后續(xù)地址變更自動(dòng)通知);
消費(fèi)端拿到地址列表后,緊接著對(duì) MetadataService 發(fā)起調(diào)用,返回結(jié)果中包含了所有應(yīng)用定義的“普通服務(wù)”及其相關(guān)配置信息;
至此,消費(fèi)者可以接收外部流量,并對(duì)提供者發(fā)起 Dubbo RPC 調(diào)用。
在以上流程中,我們只考慮了一切順利的情況,但在更詳細(xì)的設(shè)計(jì)或編碼實(shí)現(xiàn)中,我們還需要嚴(yán)格約定一些異常場景下的框架行為。比如,如果消費(fèi)者 MetadataService 調(diào)用失敗,則在重試知道成功之前,消費(fèi)者將不可以接收外部流量。
服務(wù)自省中的關(guān)鍵機(jī)制
Client 與 Server 間在收到地址推送后的配置同步是服務(wù)自省的關(guān)鍵環(huán)節(jié),目前針對(duì)元數(shù)據(jù)同步有兩種具體的可選方案,分別是:內(nèi)建 MetadataService;獨(dú)立的元數(shù)據(jù)中心,通過中細(xì)化的元數(shù)據(jù)集群協(xié)調(diào)數(shù)據(jù)。
內(nèi)建 MetadataService:MetadataService 通過標(biāo)準(zhǔn)的 Dubbo 協(xié)議暴露,根據(jù)查詢條件,會(huì)將內(nèi)存中符合條件的“普通服務(wù)”配置返回給消費(fèi)者。這一步發(fā)生在消費(fèi)端選址和調(diào)用前;
元數(shù)據(jù)中心:復(fù)用 2.7 版本中引入的元數(shù)據(jù)中心,provider 實(shí)例啟動(dòng)后,會(huì)嘗試將內(nèi)部的 RPC 服務(wù)組織成元數(shù)據(jù)的格式到元數(shù)據(jù)中心,而 consumer 則在每次收到注冊(cè)中心推送更新后,主動(dòng)查詢?cè)獢?shù)據(jù)中心。
注意 consumer 端查詢?cè)獢?shù)據(jù)中心的時(shí)機(jī),是等到注冊(cè)中心的地址更新通知之后。也就是通過注冊(cè)中心下發(fā)的數(shù)據(jù),我們能明確的知道何時(shí)某個(gè)實(shí)例的元數(shù)據(jù)被更新了,此時(shí)才需要去查元數(shù)據(jù)中心。
回顧上文講到的注冊(cè)中心關(guān)于“應(yīng)用 - 實(shí)例列表”結(jié)構(gòu)的數(shù)據(jù)組織形式,這個(gè)變動(dòng)目前對(duì)開發(fā)者并不是完全透明的,業(yè)務(wù)開發(fā)側(cè)會(huì)感知到查詢/訂閱地址列表的機(jī)制的變化。具體來說,相比以往我們基于 RPC 服務(wù)來檢索地址,現(xiàn)在 consumer 需要通過指定 provider 應(yīng)用名才能實(shí)現(xiàn)地址查詢或訂閱。
老的 Consumer 開發(fā)與配置示例:
<!-- 框架直接通過 RPC Service 1/2/N 去注冊(cè)中心查詢或訂閱地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="RPC Service 1" />
<dubbo:reference interface="RPC Service 2" />
<dubbo:reference interface="RPC Service N" />
新的 Consumer 開發(fā)與配置示例:
<!-- 框架需要通過額外的 provided-by="provider-app-x" 才能在注冊(cè)中心查詢或訂閱到地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:reference interface="RPC Service 1" provided-by="provider-app-x"/>
<dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />
<dubbo:reference interface="RPC Service N" provided-by="provider-app-y" />
以上指定 provider 應(yīng)用名的方式是 Spring Cloud 當(dāng)前的做法,需要 consumer 端的開發(fā)者顯示指定其要消費(fèi)的 provider 應(yīng)用。
以上問題的根源在于注冊(cè)中心不知道任何 RPC 服務(wù)相關(guān)的信息,因此只能通過應(yīng)用名來查詢。
為了使整個(gè)開發(fā)流程對(duì)老的 Dubbo 用戶更透明,同時(shí)避免指定 provider 對(duì)可擴(kuò)展性帶來的影響(參見下方說明),我們?cè)O(shè)計(jì)了一套 RPC 服務(wù)到應(yīng)用名的映射關(guān)系,以嘗試在 consumer 自動(dòng)完成 RPC 服務(wù)到 provider 應(yīng)用名的轉(zhuǎn)換。
Dubbo 之所以選擇建立一套“接口-應(yīng)用”的映射關(guān)系,主要是考慮到 service - app 映射關(guān)系的不確定性。一個(gè)典型的場景即是應(yīng)用/服務(wù)拆分,如上面提到的配置 <dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />,PC Service 2 是定義于 provider-app-x 中的一個(gè)服務(wù),未來它隨時(shí)可能會(huì)被開發(fā)者分拆到另外一個(gè)新的應(yīng)用如 provider-app-x-1 中,這個(gè)拆分要被所有的 PC Service 2 消費(fèi)方感知到,并對(duì)應(yīng)用進(jìn)行修改升級(jí),如改為 <dubbo:reference interface="RPC Service 2" provided-by="provider-app-x-1" />,這樣的升級(jí)成本不可否認(rèn)還是挺高的。
到底是 Dubbo 框架幫助開發(fā)者透明的解決這個(gè)問題,還是交由開發(fā)者自己去解決,當(dāng)然這只是個(gè)策略選擇問題,并且 Dubbo 2.7.5+ 版本目前是都提供了的。其實(shí)我個(gè)人更傾向于交由業(yè)務(wù)開發(fā)者通過組織上的約束來做,這樣也可進(jìn)一步降低 Dubbo 框架的復(fù)雜度,提升運(yùn)行態(tài)的穩(wěn)定性。
總結(jié)與展望
應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)機(jī)制是 Dubbo 面向云原生走出的重要一步,它幫 Dubbo 打通了與其他微服務(wù)體系之間在地址發(fā)現(xiàn)層面的鴻溝,也成為 Dubbo 適配 Kubernetes Native Service 等基礎(chǔ)設(shè)施的基礎(chǔ)。
我們期望 Dubbo 在新模型基礎(chǔ)上,能繼續(xù)保留在編程易用性、服務(wù)治理能力等方面強(qiáng)大的優(yōu)勢(shì)。但是我們也應(yīng)該看到應(yīng)用粒度的模型一方面帶來了新的復(fù)雜性,需要我們繼續(xù)去優(yōu)化與增強(qiáng);另一方面,除了地址存儲(chǔ)與推送之外,應(yīng)用粒度在幫助 Dubbo 選址層面也有進(jìn)一步挖掘的潛力。
劉軍,Github 賬號(hào) Chickenlj,Apache Dubbo PMC,項(xiàng)目核心開發(fā),見證了Dubbo從重啟開源到Apache畢業(yè)的整個(gè)流程。現(xiàn)任職阿里云云原生應(yīng)用平臺(tái)團(tuán)隊(duì),參與服務(wù)框架、微服務(wù)相關(guān)工作,目前主要在推動(dòng) Dubbo 3.0 - Dubbo 云原生。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。