引自:Dobbo 元數據中心
前言
如果讓你在本地構建一個 Dubbo 應用,你會需要額外搭建哪些中間件呢?如果沒猜錯的話,你的第一反應應該是注冊中心,類 Dubbo 的大多數服務治理框架都有注冊中心的概念。你可以部署一個 Zookeeper,或者一個 Nacos,看你的喜好。但在 Apache Dubbo 的 2.7 版本后,額外引入了兩個中間件:元數據中心和配置中心。
在今年年初 Dubbo 2.7 剛發布時,我就寫了一篇文章 《Dubbo 2.7 三大新特性詳解》,介紹了包含元數據中心改造在內的三大新特性,但一些細節介紹沒有詳細呈現出來,在這篇文章中,我將會以 Dubbo 為例,跟大家一起探討一下服務治理框架中元數據中心的意義與集成細節。

元數據中心介紹
服務治理中的元數據(Metadata)指的是服務分組、服務版本、服務名、方法列表、方法參數列表、超時時間等,這些信息將會存儲在元數據中心之中。與元數據平起平坐的一個概念是服務的注冊信息,即:服務分組、服務版本、服務名、地址列表等,這些信息將會存儲在注冊中心中。稍微一對比可以發現,元數據中心和注冊中心存儲了一部分共同的服務信息,例如服務名。兩者也有差異性,元數據中心還會存儲方法列表即參數列表,注冊中心存儲了服務地址。上述的概述,體現出了元數據中心和注冊中心在服務治理過程中,擔任着不同的角色。為了有一個直觀的對比,我整理出了下面的表格:
元數據 |
注冊信息 |
|
---|---|---|
職責 |
描述服務,定義服務的基本屬性 |
存儲地址列表 |
變化頻繁度 |
基本不變 |
隨着服務上下線而不斷變更 |
數據量 |
大 |
小 |
數據交互/存儲模型 |
消費者/提供者上報,控制台查詢 |
PubSub 模型,提供者上報,消費者訂閱 |
主要使用場景 |
服務測試、服務 MOCK |
服務調用 |
可用性要求 |
元數據中心可用性要求不高,不影響主流程 |
注冊中心可用性要求高,影響到服務調用的主流程 |
下面我會對每個對比點進行單獨分析,以加深對元數據中心的理解。
職責
在 Dubbo 2.7 版本之前,並沒有元數據中心的概念,那時候注冊信息和元數據都耦合在一起。Dubbo Provider 的服務配置有接近 30 個配置項,排除一部分注冊中心服務治理需要的參數,很大一部分配置項僅僅是 Provider 自己使用,不需要透傳給消費者;Dubbo Consumer 也有 20 多個配置項。在注冊中心之中,服務消費者列表中只需要關注 application,version,group,ip,dubbo 版本等少量配置。這部分數據不需要進入注冊中心,而只需要以 key-value 形式持久化存儲在元數據中心即可。從職責來看,將不同職責的數據存儲在對應的組件中,會使得邏輯更加清晰。
變化頻繁度
注冊信息和元數據耦合在一起會導致注冊中心數據量的膨脹,進而增大注冊中心的網絡開銷,直接造成了服務地址推送慢等負面影響。服務上下線會隨時發生,變化的其實是注冊信息,元數據是相對不變的。
數據量
由於元數據包含了服務的方法列表以及參數列表,這部分數據會導致元數據要比注冊信息大很多。注冊信息被設計得精簡會直接直接影響到服務推送的 SLA。
數據交互/存儲模型
注冊中心采用的是 PubSub 模型,這屬於大家的共識,所以注冊中心組件的選型一般都會要求其有 notify 的機制。而元數據中心並沒有 notify 的訴求,一般只需要組件能夠提供 key-value 的存儲結構即可。
主要使用場景
在服務治理中,注冊中心充當了通訊錄的職責,在復雜的分布式場景下,讓消費者能找到提供者。而元數據中心存儲的元數據,主要適用於服務測試、服務 MOCK 等場景,這些場景都對方法列表、參數列表有所訴求。在下面的小節中,我也會對使用場景進行更加詳細的介紹。
可用性要求
注冊中心宕機或者網絡不通會直接影響到服務的可用性,它影響了服務調用的主路徑。但一般而言,元數據中心出現問題,不會影響到服務調用,它提供的能力是可被降級的。這也闡釋了一點,為什么很多用戶在 Dubbo 2.7 中沒有配置元數據中心,也沒有影響到正常的使用。元數據中心在服務治理中扮演的是錦上添花的一個角色。在組件選型時,我們一般也會對注冊中心的可用性要求比較高,元數據中心則可以放寬要求。
元數據中心的價值
小孩子才分對錯,成年人只看利弊。額外引入一個元數據中心,必然帶來運維成本、理解成本、遷移成本等問題,那么它具備怎樣的價值,來說服大家選擇它呢?上面我們介紹元數據中心時已經提到了服務測試、服務 MOCK 等場景,這一節我們重點探討一下元數據中心的價值。
降低地址推送的時延
由於注冊中心采用的是 PubSub 模型,數據量的大小會直接影響到服務地址推送時間,不知道你有沒有遇到過 No provider available
的報錯呢?明明提供者已經啟動了,但由於注冊中心推送慢會導致很多問題,一方面會影響到服務的可用性,一方面也會增加排查問題的難度。
在一次杭州 Dubbo Meetup 中,網易考拉分享了他們對 Zookeeper 的改造,根源就是
推送量大 -> 存儲數據量大 -> 網絡傳輸量大 -> 延遲嚴重
這一實際案例佐證了元數據改造並不是憑空產生的需求,而是切實解決了一個痛點。
服務測試 & 服務 MOCK
在 Dubbo 2.7 之前,雖然注冊中心耦合存儲了不少本應屬於元數據的數據,但也漏掉了一部分元數據,例如服務的方法列表,參數列表。這些是服務測試和服務 MOCK 必備的數據,想要使用這些能力,就必須引入元數據中心。例如開源的 Dubbo Admin 就實現了服務測試功能,用戶可以在控制台上對已經發布的服務提供者進行功能測試。可能你之前有過這樣的疑惑:為什么只有 Dubbo 2.7 才支持了服務測試呢?啊哈,原因就是 Dubbo 2.7 才有了元數據中心的概念。當然,服務 MOCK 也是如此。

其他場景
可以這么理解,任何依賴元數據的功能,都需要元數據中心的支持。其他場景還包括了網關應用獲取元數據來進行泛化調用、服務自動化測試等等。再描述一個可能的場景,拋磚引玉。在一次南京 Dubbo Meetup 上,dubbo.js 的作者提及的一個場景,希望根據元數據自動生成 NodeJs 代碼,以簡化前端的開發量,也是元數據的作用之一。這里就需要發揮各位的想象力了
Dubbo 配置元數據中心
目前 Dubbo 最新的版本為 2.7.4,目前支持的幾種元數據中心可以從源碼中得知(官方文檔尚未更新):

支持 consul、etcd、nacos、redis、zookeeper 這五種組件。
配置方式如下:
dubbo.metadata-report.address=nacos://127.0.0.1:8848
元數據存儲格式剖析
前面我們介紹了元數據中心的由來以及價值,還是飄在天上的概念,這一節將會讓概念落地。元數據是以怎么樣一個格式存儲的呢?
以 DemoService 服務為例:
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" executes="4500" retries="7" owner="kirito"/> <dubbo:registry address="zookeeper://127.0.0.1:2181" />
首先觀察在 Dubbo 2.6.x 中,注冊中心如何存儲這個服務的信息:
dubbo://30.5.120.185:20880/com.alibaba.dubbo.demo.DemoService? anyhost=true& application=demo-provider& interface=com.alibaba.dubbo.demo.DemoService& methods=sayHello& bean.name=com.alibaba.dubbo.demo.DemoService& dubbo=2.0.2&executes=4500& generic=false&owner=kirito& pid=84228&retries=7&side=provider×tamp=1552965771067
例如 bean.name
和 owner
這些屬性,肯定是沒必要注冊上來的。
接着,我們在 Dubbo 2.7 中使用最佳實踐,為 registry 配置 simplified=true:
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" executes="4500" retries="7" owner="kirito"/> <dubbo:registry address="zookeeper://127.0.0.1:2181" simplified="true" /> <dubbo:metadata-report address="nacos://127.0.0.1:8848"/>
之后再觀察注冊中心的數據,已經變得相當精簡了:
dubbo://30.5.120.185:20880/org.apache.dubbo.demo.api.DemoService? application=demo-provider& dubbo=2.0.2& release=2.7.0& timestamp=1552975501873
被精簡省略的數據不代表沒有用了,而是轉移到了元數據中心之中,我們觀察一下此時元數據中心中的數據:

最佳實踐
元數據中心是服務治理中的一個關鍵組件,但對於大多數用戶來說還是一個比較新的概念,我整理了一些我認為的最佳實踐,分享給大家。
- 從 Dubbo 2.6 遷移到 Dubbo 2.7 時,可以采取三步走的策略來平滑遷移元數據。第一步:Dubbo 2.6 + 注冊中心,第二步:Dubbo 2.7 + 注冊中心 + 元數據中心,第三步:Dubbo 2.7 + 注冊中心(simplified=true) + 元數據中心。在未來 Dubbo 的升級版本中,registry 的 simplified 默認值將會變成 true,目前是 false,預留給用戶一個升級的時間。
- 應用在啟動時,會發布一次元數據,在此之后會有定時器,一天同步一次元數據,以上報那些運行時生成的 Bean,目前用戶不可以配置元數據上報的周期,但可以通過
-Dcycle.report
關閉這一定時器。 - 元數據中心推薦選型:Nacos 和 Redis。