小白也能看懂的dubbo3應用級服務發現詳解


搜索關注微信公眾號"捉蟲大師",后端技術分享,架構設計、性能優化、源碼閱讀、問題排查、踩坑實踐。

本文已收錄 https://github.com/lkxiaolou/lkxiaolou 歡迎star。

dubbo 是一款開源的 RPC 框架,主要有3個角色: 提供者(provider)消費者(consumer)注冊中心(registry)

image
提供者啟動時向注冊中心注冊服務地址,消費者啟動時訂閱服務,並通過獲取到的提供者地址發起調用,當提供者地址變更時,通過注冊中心向消費者推送變更。這就是 dubbo 主要的工作流程。

在2.7.5之前,dubbo 只支持接口級服務發現模型,>=2.7.5的版本提供了接口級與應用級兩種服務發現模型,3.0之后的版本應用級服務發現更是非常重要的一個功能。

本文將從為什么需要引入應用級服務發現,dubbo 實現應用級服務發現的難點以及dubbo3 是如何解決這些問題這三個部分進行講解。

開始前,我們先了解下 dubbo 最初提供的接口級服務發現是怎樣的。

接口級服務發現長啥樣?

dubbo 服務的注冊發現是以接口為最小粒度的,在 dubbo 中將其抽象為一個URL,大概長這樣:

dubbo://10.1.1.123:20880/org.newboo.basic.api.MyDemoService?anyhost=true&application=ddog-my-demo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.newboo.basic.api.MyDemoService&methods=setUser,getUser&owner=roshilikang&release=2.7.6&side=provider&threads=500

看着很亂?捋一捋:

image

  • 協議代表提供服務的協議,如果注冊了 grpc 服務,這里就是 grpc://

  • ipport 代表是哪台機器的哪個端口提供服務

  • interface 代表了注冊的接口名,它直接對應到代碼中需要暴露服務的 interface,如下:

package org.newboo.basic.api;

import org.newboo.basic.model.User;

public interface MyDemoService {
    void setUser(User user);
    User getUser(String uid);
}
  • 參數代表了服務的一些參數,可能是元數據,也可能是配置信息

細心的你一定發現了,一個 interface 可以包含多個 dubbo 接口,所以把它稱為接口級服務發現有些不妥,應該是服務級服務發現,但服務的定義比較模糊,可能會被誤認為是應用,甚至后面介紹的 dubbo 應用級服務發現使用的關鍵字也是 service,所以我們用接口級這個更加易懂的概念來代替。

接口級服務發現有什么問題?

數據太多

無論是存儲還是變更推送壓力都可能遇到瓶頸,數據多表現在這兩個方面:

  • 注冊的單條數據太大

這個問題好解決:拆!

dubbo 在 2.7 之后的版本支持了元數據中心配置中心,對於URL的參數進行分類存儲。持久不變的(如application、method等)參數存儲到元數據中心中,可能在運行時變化(timeout、tag)的存儲到配置中心中

image

  • 注冊數據條數太多

image
無論是增加一台機器還是增加一個接口,其增長都是線性的,這個問題比單條數據大更嚴重。

當抹去注冊信息中的 interface 信息,這樣數據量就大大減少

image

非主流

只用過 dubbo 的同學可能覺得這很主流。

但從服務發現的角度來看:

無論是用的最多的服務注冊發現系統 DNS,又或者是 SpringCloud 體系、K8S 體系,都是以應用為維度進行服務注冊發現的,只有和這些體系對齊,才能更好地與之進行打通。

在我了解的范圍里,目前只有 dubboSOFARPCHSF 三個阿里系的 RPC 框架支持了接口級的服務發現。

接口級服務發現如何使用

provider端暴露服務:

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

<dubbo:service interface="org.newboo.basic.api.MyDemoService" ref="myNewbooDemoService"/>

consumer端引用服務:

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

<dubbo:reference id="myNewbooDemoService" interface="org.newboo.basic.api.MyDemoService"/>

image
本地調用遠程的方法時,只需要配置一個 reference,然后直接使用 interface 來調用,我們不必去實現這個 interaface,dubbo 自動幫我們生成了一個代理進行 RPC 調用,屏蔽了通信的細節,讓我們有種像調用本地方法一樣調用遠程方法的感覺,這也是 dubbo 的優勢。

從這里我們能看出為什么 dubbo 要設計成接口級服務發現,因為要為每一個 interface 生成一個代理,就必須定位到該 interface 對應服務暴露的服務地址,為了方便,dubbo 就這么設計了。

如果要實現應用級服務發現你會怎么做?

如果讓我來設計應用級服務發現,注冊不必多說,按應用名注冊即可。

但這里有個隱藏問題是應用名的唯一性,應用名必須得很好的管理起來,否則重復、隨意改動都可能導致服務發現失效

至於訂閱,在目前 dubbo 機制下,必須得告訴消費者消費的每個接口是屬於哪個應用,這樣才能定位到接口部署在哪里。

難點是什么

實現 dubbo 應用級服務發現,難點在於

  • 兼容性,除了服務發現,其他改動點盡量少,且能兼容接口級到應用級的過渡
  • 接口到應用的部署關系,在接口級服務發現中,是不需要關心接口部署在哪個應用上的,但換做應用級,必須得知道這點,但這點就增加了開發者的使用難度,有沒有方案盡量屏蔽細節?

image

dubbo3 是如何解決這些問題的?

兼容性

保留接口級服務發現,且默認采取雙注冊方式,可配置使用哪種服務發現模型,如下配置使用應用級服務發現

<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>

居然使用了service這個關鍵字😅

如何查找接口對應的應用

  • 方案1:手動配置,實現簡單,架構簡單,但用戶使用成本高,這種方式 dubbo3 已支持
<dubbo:service services="ddog-my-demo-p0" interface="org.newboo.basic.api.MyDemoService" ref="myNewbooDemoService"/>
  • 方案2:服務自省

名詞有點高大上,但道理很簡單,讓 dubbo 自己去匹配,提供者注冊的時候把接口和應用名的映射關系存儲起來,消費者消費時根據接口名獲取到部署的應用名,再去做服務發現。

數據存儲在哪里?顯然元數據中心非常合適。該方案用戶使用起來和之前接口級沒有任何不同,但需要增加一個元數據中心,架構變得復雜。

且有一個問題是,如果接口在多個應用下部署了,dubbo 查找的策略是都去訂閱,這可能在某些場景下不太合適。

image

最后

本文從接口級服務發現講到應用級服務發現,包含了為什么 dubbo 設計成接口級服務發現,接口級服務發現有什么痛點?基於 dubbo 現狀如何設計應用級服務發現,應用級服務發現實現有什么難點等等問題進行解答,相信看完的小伙伴一定有所收獲。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM