Dubbo第二天

4. Dubbo 高級(jí)特性

4.1Dubbo 控制臺(tái)部署

從 2.6 版本之后,dubbo 控制臺(tái)已單獨(dú)版本管理(目前只到 0.1 版本),使用了前后端分離的模式。前端使用 Vue 和 Vuetify 分別作為 Javascript 框架和 UI 框架,后端采用 Spring Boot 框架??紤]到后端人員操作的簡(jiǎn)易性,本文只介紹 Maven 部署方案(即將前端 vue產(chǎn)出的靜態(tài)內(nèi)容集成到 springboot 包內(nèi))。

? 下載:git clone https://github.com/apache/dubbo-admin.git

在 dubbo-admin-server 子項(xiàng)目的屬性文件中,設(shè)置 zk 地址及登陸帳戶/密碼:

? 編譯:

cd dubbo-admin

mvn clean package? ?##編譯時(shí)間稍長(zhǎng),請(qǐng)耐心等待(前提是配置好你的 maven 環(huán)境)

? 啟動(dòng):

cd dubbo-admin-distribution/target

java -jar dubbo-admin-0.1.jar?

? 訪問:

http://localhost:8080

? 條件路由的使用示例:

查詢服務(wù)列表后,對(duì)目標(biāo)服務(wù)添加路由:

點(diǎn)擊創(chuàng)建按鈕后,如下填寫條件信息:

保存后測(cè)試,你會(huì)發(fā)現(xiàn)消費(fèi)方已無法調(diào)用此服務(wù)。

4.2啟動(dòng)時(shí)檢查

Dubbo 缺省會(huì)在啟動(dòng)時(shí)檢查依賴的服務(wù)是否可用,不可用時(shí)會(huì)拋出異常,阻止 Spring 初始化完成,以便上線時(shí),能及早發(fā)現(xiàn)問題,默認(rèn) check="true"可以通過 check="false"關(guān)閉檢查,比如,測(cè)試時(shí),有些服務(wù)不關(guān)心,或者出現(xiàn)了循環(huán)依賴,必須有一方先啟動(dòng);

另外,如果你的 Spring 容器是懶加載的,或者通過 API 編程延遲引用服務(wù),請(qǐng)關(guān)閉 check,否則服務(wù)臨時(shí)不可用時(shí),會(huì)拋出異常,拿到 null 引用,如果check="false",總是會(huì)返回引用,當(dāng)服務(wù)恢復(fù)時(shí),能自動(dòng)連上。

? 關(guān)閉某個(gè)服務(wù)的啟動(dòng)時(shí)檢查(沒有提供者時(shí)報(bào)錯(cuò)):

<dubbo:reference id="xxxService" check="false" interface="com.xxx.XxxService"/>

? 關(guān)閉所有服務(wù)的啟動(dòng)時(shí)檢查(沒有提供者時(shí)報(bào)錯(cuò)):

<dubbo:consumer check="false" />

? 關(guān)閉注冊(cè)中心啟動(dòng)時(shí)檢查(注冊(cè)訂閱失敗時(shí)報(bào)錯(cuò)):

<dubbo:registry check="false" />

4.3Dubbo 超時(shí)重連

4.3.1 超時(shí)

Dubbo 消費(fèi)端在發(fā)出請(qǐng)求后,需要有一個(gè)臨界時(shí)間界限來判斷服務(wù)端是否正常。這樣消費(fèi)端達(dá)到超時(shí)時(shí)間,那么 Dubbo 會(huì)進(jìn)行重試機(jī)制,不合理的重試在一些特殊的業(yè)務(wù)場(chǎng)景下可能會(huì)引發(fā)很多問題,需要合理設(shè)置接口超時(shí)時(shí)間。

Dubbo 超時(shí)和重試配置示例:

<!-- 服務(wù)調(diào)用超時(shí)設(shè)置為 5 秒,超時(shí)不重試-->

<dubbo:reference id="xxxService" interface="com.xxx.XxxService" retries="0" timeout="5000"/>

4.3.2 重連

Dubbo 在調(diào)用服務(wù)不成功時(shí),默認(rèn)會(huì)重試 2 次;

Dubbo 的路由機(jī)制,會(huì)把超時(shí)的請(qǐng)求路由到其他機(jī)器上,而不是本機(jī)嘗試,所以 Dubbo 的重試機(jī)制也能一定程度的保證服務(wù)的質(zhì)量。

4.4 集群容錯(cuò)

當(dāng)消費(fèi)端某次調(diào)用失敗是一些環(huán)境偶然因素造成的(如網(wǎng)絡(luò)抖動(dòng)),dubbo還給予了容錯(cuò)補(bǔ)救機(jī)會(huì)。補(bǔ)救方式存在以下幾種:

<dubbo:consumer cluster="failover” retries="2" forks="2" />

1、 Failover :當(dāng)出現(xiàn)失敗,重試其它服務(wù)器。 retries=“2” 來設(shè)置重試次數(shù)(不含第一次)。

冪等性操作使用,如讀操作。

2、 Failfast :快速失敗,只發(fā)起一次調(diào)用,失敗立即報(bào)錯(cuò)。

非冪等性操作,如寫操作。

3、 Failsafe :出現(xiàn)異常時(shí),直接忽略。

無關(guān)緊要的旁支操作,如打日志。

4、 Failback :后臺(tái)記錄失敗請(qǐng)求,定時(shí)重發(fā)。

后續(xù)專業(yè)處理。

5、 Forking :并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回。

forks=“2” 來設(shè)置最大并行數(shù)。

4.5負(fù)載均衡配置

在集群負(fù)載均衡時(shí),Dubbo 提供了多種均衡策略,缺省為 random 隨機(jī)調(diào)用。

可以自行擴(kuò)展負(fù)載均衡策略:

<dubbo:consumer loadbalance="random"/>

1、 Random :按權(quán)重隨機(jī)------根據(jù) weight 值(服務(wù)方設(shè)置)來隨機(jī)--

2、 RoundRobin :輪詢

3、 LeastActive :最少活躍數(shù)(正在處理的數(shù)),慢的機(jī)器,收到的請(qǐng)求少

4.6結(jié)果緩存

dubbo 對(duì)方法調(diào)用的結(jié)果,還有緩存功能。在服務(wù)消費(fèi)方和提供方都可以配置使用緩存。

以消費(fèi)方為例,可以配置全局緩存策略,這樣所有服務(wù)引用都啟動(dòng)緩存:

<dubbo:consumer cache="lru"/>

還可以僅對(duì)某個(gè)服務(wù)引用配置緩存策略;

<dubbo:reference id="xxxService" interface="com.xxx.XxxService" cache="lru" >

還支持對(duì)單個(gè)方法啟用緩存策略;

<dubbo:reference id="xxxService" interface="com.xxx.XxxService" >

<dubbo:method name="sayHello" cache="lru"> </dubbo:method>

</dubbo:reference>

服務(wù)方配置方法與消費(fèi)端完全一樣。

4.7服務(wù)分組

比如,想在同一個(gè)注冊(cè)中心中,分隔測(cè)試和開發(fā)環(huán)境(省一套注冊(cè)服務(wù)):

<dubbo:consumer group ="dev"/>

<dubbo:provider group ="dev"/>

只要 group 按開發(fā)組和測(cè)試組對(duì)應(yīng),同一個(gè)注冊(cè)中心里的兩套服務(wù)就互不干擾

4.8多版本

服務(wù)端提供接口的實(shí)現(xiàn)升級(jí)時(shí),可由 dubbo 的版本號(hào)操作進(jìn)行過渡。如果上線上測(cè)試新版本接口有缺陷,為了不影響業(yè)務(wù),要迅速切回原版本接口,最大程度減少損失。

服務(wù)方:

<!--版本 1 接口-->

<dubbo:service interface="com.xxx.XxxServices" ref="xxxService" protocol="hessian" version="1.0"/>

<!--版本 2 接口-->

<dubbo:service interface="com.xxx.XxxServices" ref="xxxService2" protocol="hessian" version="2.0"/>

消費(fèi)方:

<dubbo:reference id="xxxService1.0"

interface="com.xxx.XxxServices" protocol="hessian" version="2.0"/>

4.9只訂閱/只注冊(cè)

4.9.1 只訂閱

場(chǎng)景:我們?cè)诒镜亻_發(fā)的時(shí)候,不能把自己機(jī)器的未開發(fā)好的服務(wù)注冊(cè)到開發(fā)環(huán)境,但是又需要使用注冊(cè)中心的其他服務(wù)。

服務(wù)提供者配置禁止注冊(cè): register="false"?

<dubbo:registry protocol="zookeeper" register="false"/>

4.9.2 只注冊(cè)

比如開發(fā)環(huán)境為了省機(jī)器,沒有部署某個(gè)服務(wù),如短信/郵件功能。但整個(gè)系統(tǒng)又必須要調(diào)用它。此時(shí)我們可以借用一下測(cè)試環(huán)境的此服務(wù)(不能影響測(cè)試環(huán)境原本的服務(wù)閉環(huán))。將測(cè)試環(huán)境的短信/郵件服務(wù)也向開發(fā)環(huán)境注冊(cè)一份,只注冊(cè)(其依賴的服務(wù)必須還是測(cè)試環(huán)境的)。

服務(wù)提供者配置禁止訂閱: subscribe="false"?

<dubbo:registry protocol="zookeeper" subscribe="false"/>

4.10異步調(diào)用

Dubbo 的異步調(diào)用是非阻塞的 NIO 調(diào)用,一個(gè)線程可同時(shí)并發(fā)調(diào)用多個(gè)遠(yuǎn)程服務(wù),每個(gè)服務(wù)的調(diào)用都是非阻塞的,線程立即返回。就是對(duì)java中Futrue模式的擴(kuò)展支持:

如上圖,userThread 發(fā)出調(diào)用后,IOThread 會(huì)立即返回,并在 RPC 上下文RpcContext中設(shè)置Future。userThread后續(xù)可以從RpcContext中取得此Future,然后 wait 這個(gè) Future 其它的事情都由 IOThread 完成。

總之,userThread 發(fā)出調(diào)用后 IOThread 會(huì)立刻返回,而不是等調(diào)用在服務(wù)端執(zhí)行完代碼、返回結(jié)果后返回。用戶返回后可以去做點(diǎn)其它事情,比如調(diào)用另外一個(gè)服務(wù),然后回頭等待前一個(gè)調(diào)用完成。從上圖可以看出,異步調(diào)用完全是 Consumer 端的行為。

配置:

<dubbo:reference id="xxxService" interface="com.xxx.XxxService">

<dubbo:method name="doSomething" async="true" />

</dubbo:reference>

async=true 表示異步調(diào)用,可以看到配置發(fā)生在 Consumer 端,能精確到方法。

方法異步調(diào)用后,Consumer 端的代碼寫法:

// 此方法異步后不再有返回值,會(huì)立刻返回 NULL

xxxService.doSomething(xxx);

// 立刻得到當(dāng)前調(diào)用的 Future 實(shí)例,當(dāng)發(fā)生新的調(diào)用時(shí)這個(gè)東西將會(huì)被覆蓋

Future<XXX> xxxFuture = RpcContext.getContext().getFuture();

// 等待調(diào)用完成,線程會(huì)進(jìn)入 Sleep 狀態(tài),當(dāng)調(diào)用完成后被喚醒。

Foo foo = fooFuture.get();

配置是否等待 IOThread 發(fā)送完 Request 后再返回:

? sent="true" ,等待請(qǐng)求發(fā)送出去后再返回,如果發(fā)送失敗直接拋出異常。

? sent="false" ,將調(diào)用交給 IOThread 后立即返回。實(shí)際這個(gè)時(shí)候請(qǐng)求進(jìn)入到 IOThread 的隊(duì)列,排除等著被發(fā)送出去。

<dubbo:method name="xxx" async="true" sent="true" />

如果對(duì)返回結(jié)果沒有興趣:

<dubbo:method name="xxx" async="true" return="false" />

4.11事件通知

對(duì)于一次遠(yuǎn)程方法調(diào)用,有 oninvoke、onreturn、onthrow 三個(gè)事件,分別為調(diào)用之前、返回之后,拋出異常三個(gè)事件。在 Consumer 端,可以為三個(gè)事件指定事件處理方法。

首先,需要在 SpringIOC 容器中,創(chuàng)建一個(gè)實(shí)現(xiàn)了回調(diào)接口的 Bean,假設(shè) id=callback:

interface Callback {

????public void onreturn(Person msg, Integer id);

????public void onthrow(Throwable ex, Integer id);

}

方法中,第一個(gè)參數(shù)是遠(yuǎn)程方法的返回值,其它是方法的參數(shù)。

然后在 Dubbo 中配置:

<dubbo:reference interface="com.xxx.XxxService" >

????<dubbo:method name="doSomeThing" async="true" onreturn = "callback.onreturn" ????onthrow="callback.onthrow" />

</dubbo:reference>

配置中 async 與 onreturn、onthrow 是成對(duì)配置,組合不同,功能也不同:

? 異步回調(diào)模式:async=true onreturn="xxx"

? 同步回調(diào)模式:async=false onreturn="xxx"

? 異步無回調(diào) :async=true

? 同步無回調(diào) :async=false

4.12 Provider 端應(yīng)盡量配置的屬性

Dubbo 的屬性配置優(yōu)先度上,遵循如下順序:

reference 屬性 > service 屬性 >Consumer 屬性;

其中 reference 和 Consumer 是消費(fèi)端配置,service 是服務(wù)端配置而對(duì)于服務(wù)調(diào)用的超時(shí)時(shí)間、重試次數(shù)等屬性,服務(wù)的提供方比消費(fèi)方更了解服務(wù)性能,因此我們應(yīng)該在 Provider 端盡量多配置 Consumer 端屬性,讓其漫游到消費(fèi)端發(fā)揮作用。

Provider 端盡量多配置 Consumer 端的屬性,也讓 Provider 的實(shí)現(xiàn)者一開始就思考 Provider 端的服務(wù)特點(diǎn)和服務(wù)質(zhì)量等問題。

建議在 Provider 端配置的 Consumer 端屬性有:

timeout:方法調(diào)用的超時(shí)時(shí)間

retries:失敗重試次數(shù)

loadbalance:負(fù)載均衡算法,缺省是隨機(jī) random。

actives:消費(fèi)者端的最大并發(fā)調(diào)用限制,即當(dāng) Consumer 對(duì)一個(gè)服務(wù)的并發(fā)調(diào)用到上限后,新調(diào)用會(huì)阻塞直到超時(shí),在方法上配置 dubbo:method 則針對(duì)該方法進(jìn)行并發(fā)限制,在接口上配置 dubbo:service,則針對(duì)該服務(wù)進(jìn)行并發(fā)限制。

<dubbo:service interface="com.xxx.xxxService" timeout="300" retries="2" ????loadbalance="random" actives="0" >

<dubbo:method name="xxx" timeout="10000" retries="9" loadbalance="leastactive" ????actives="5" />

<dubbo:service/>?

建議在 Provider 端配置的 Provider 端屬性有:

threads:服務(wù)線程池大小。

executes:一個(gè)服務(wù)提供者并行執(zhí)行請(qǐng)求上限,即當(dāng) Provider 對(duì)一個(gè)服務(wù)的并發(fā)調(diào)用達(dá)到上限后,新調(diào)用會(huì)阻塞,此時(shí) Consumer 可能會(huì)超時(shí)。

在方法上配置 dubbo:method 則針對(duì)該方法進(jìn)行并發(fā)限制;

在接口上配置dubbo:service,則針對(duì)該服務(wù)進(jìn)行并發(fā)限制。

<dubbo:protocol threads="200" />

<dubbo:service interface="com.xxx.xxxService" version="1.0.0" ref="xxxService" ????executes="200" >

<dubbo:method name="xxx" executes="50" />

</dubbo:service>

4.13服務(wù)拆分最佳實(shí)現(xiàn)

分包

建議將服務(wù)接口、服務(wù)模型、服務(wù)異常等均放在 API 包中,因?yàn)榉?wù)模型和異常也是 API 的一部分,這樣做也符合分包原則:重用發(fā)布等價(jià)原則(REP:復(fù)用的粒度即是發(fā)布的粒度,我們所重用的任何東西必須同時(shí)被發(fā)布和跟蹤),共同重用原則(CRP:如果你重用了一個(gè)組件中的一個(gè)類,那么就要重用包中的所有類)。?

粒度

服務(wù)接口盡可能大粒度,每個(gè)服務(wù)方法應(yīng)代表一個(gè)功能,而不是某功能的一個(gè)步驟,否則將面臨分布式事務(wù)問題,Dubbo 暫未提供分布式事務(wù)支持。

不建議使用過于抽象的通用接口,如:Map query(Map),這樣的接口沒有明確語(yǔ)義,會(huì)給后期維護(hù)帶來不便。

版本

每個(gè)接口都應(yīng)定義版本號(hào),為后續(xù)不兼容升級(jí)提供可能,如:

<dubbo:service interface="com.xxx.XxxService"? ? version="1.0" />。

建議使用兩位版本號(hào),因?yàn)榈谌话姹咎?hào)通常表示兼容升級(jí),只有不兼容時(shí)才需要變更服務(wù)版本。當(dāng)不兼容時(shí),先升級(jí)一半提供者為新版本,再將消費(fèi)者全部升為新版本,然后將剩下的一半提供者升為新版本。

異常

建議使用異常匯報(bào)錯(cuò)誤,而不是返回錯(cuò)誤碼,異常信息能攜帶更多信息,并且語(yǔ)義更友好。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • dubbo.xsd 文件說明 當(dāng)我們要使用Dubbo進(jìn)行 配置時(shí),需要像下面那樣引入dubbo.xsd這個(gè)文件. ...
    Mis_Gtw閱讀 1,165評(píng)論 0 1
  • 主要內(nèi)容 1.Dubbo簡(jiǎn)介 2.Dubbo架構(gòu)講解 3.Dubbo支持的協(xié)議 4.Dubbo支持的注冊(cè)中心 5....
    w漫漫閱讀 641評(píng)論 0 0
  • 官方文檔 快速啟動(dòng) 關(guān)鍵配置 啟動(dòng)類 XML配置-標(biāo)簽的含義-配置的優(yōu)先級(jí) dubbo-admin搭建-githu...
    巨子聯(lián)盟閱讀 20,010評(píng)論 3 7
  • 漸變的面目拼圖要我怎么拼? 我是疲乏了還是投降了? 不是不允許自己墜落, 我沒有滴水不進(jìn)的保護(hù)膜。 就是害怕變得面...
    悶熱當(dāng)乘涼閱讀 4,480評(píng)論 0 13
  • 感覺自己有點(diǎn)神經(jīng)衰弱,總是覺得手機(jī)響了;屋外有人走過;每次媽媽不聲不響的進(jìn)房間突然跟我說話,我都會(huì)被嚇得半死!一整...
    章魚的擁抱閱讀 2,387評(píng)論 4 5

友情鏈接更多精彩內(nèi)容