本文將詳細(xì)分析< dubbo:service executes=”“/>與< dubbo:reference actives = “”/>的實現(xiàn)機制,深入探討Dubbo自身的保護機制。

1、源碼分析ExecuteLimitFilter

@Activate(group = Constants.PROVIDER, value = Constants.EXECUTES_KEY )


過濾器作用

服務(wù)調(diào)用方并發(fā)度控制。

使用場景

對Dubbo服務(wù)提供者實現(xiàn)的一種保護機制,控制每個服務(wù)的最大并發(fā)度。

阻斷條件

當(dāng)服務(wù)調(diào)用超過允許的并發(fā)度后,直接拋出RpcException異常。

接下來源碼分析ExecuteLimitFilter的實現(xiàn)細(xì)節(jié)。

ExecuteLimitFilter#invoke


代碼@1:從服務(wù)提供者列表中獲取參數(shù)executes的值,如果該值小于等于0,表示不啟用并發(fā)度控制,直接沿著調(diào)用鏈進行調(diào)用。

代碼@2:根據(jù)服務(wù)提供者url和服務(wù)調(diào)用方法名,獲取RpcStatus。


這里是并發(fā)容器ConcurrentHashMap的經(jīng)典使用,從 這里可以看出ConcurrentMap< String, ConcurrentMap< String, RpcStatus>> METHOD_STATISTICS的存儲結(jié)構(gòu)為 { 服務(wù)提供者URL唯一字符串:{方法名:RpcStatus} }。

代碼@3:根據(jù)服務(wù)提供者配置的最大并發(fā)度,創(chuàng)建該服務(wù)該方法對應(yīng)的信號量對象。


使用了雙重檢測來創(chuàng)建executesLimit 信號量。

代碼@4:如果獲取不到鎖,并不會阻塞等待,而是直接拋出RpcException,服務(wù)端的策略是快速拋出異常,供服務(wù)調(diào)用方(消費者)根據(jù)集群策略進行執(zhí)行,例如重試其他服務(wù)提供者。

代碼@5:執(zhí)行真實的服務(wù)調(diào)用。

代碼@6:如果成功申請到信號量,在服務(wù)調(diào)用結(jié)束后,釋放信號量。

總結(jié):< dubbo:service executes=”“/>的含義是,針對每個服務(wù)每個方法的最大并發(fā)度。如果超過該值,則直接拋出RpcException。


2、源碼分析ActiveLimitFilter

@Activate(group = Constants.CONSUMER, value = Constants.ACTIVES_KEY )


過濾器作用

消費端調(diào)用服務(wù)的并發(fā)控制。

使用場景

控制同一個消費端對服務(wù)端某一服務(wù)的并發(fā)調(diào)用度,通常該值應(yīng)該小于< dubbo:service executes=”“/>

阻斷條件

非阻斷,但如果超過允許的并發(fā)度會阻塞,超過超時時間后將不再調(diào)用服務(wù),而是直接拋出超時。

源碼分析ActiveLimitFilter的實現(xiàn)原理:

ActiveLimitFilter#invoke

代碼@1:從Invoker中獲取消息端URL中的配置的actives參數(shù),為什么從Invoker中獲取的Url是消費端的Url呢?這是因為在消費端根據(jù)服務(wù)提供者URL創(chuàng)建調(diào)用Invoker時,會用服務(wù)提供者URL,然后合并消費端的配置屬性,其優(yōu)先級 -D > 消費端 > 服務(wù)端。其代碼位于:、

RegistryDirectory#toInvokers

URL url = mergeUrl(providerUrl);

代碼@2:根據(jù)服務(wù)提供者URL和調(diào)用服務(wù)提供者方法,獲取RpcStatus。

代碼@3:獲取接口調(diào)用的超時時間,默認(rèn)為1s。

代碼@4:獲取當(dāng)前消費者,針對特定服務(wù),特定方法的并發(fā)調(diào)用度,active值。

代碼@5:如果當(dāng)前的并發(fā) 調(diào)用大于等于允許的最大值,則針對該RpcStatus申請鎖,并調(diào)用其wait(timeout)進行等待,也就是在接口調(diào)用超時時間內(nèi),還是未被喚醒,則直接拋出超時異常。

代碼@6:判斷被喚醒的原因是因為等待超時,還是由于調(diào)用結(jié)束,釋放了”名額“,如果是超時喚醒,則直接拋出異常。

代碼@7:在一次服務(wù)調(diào)用前,先將 服務(wù)名+方法名對應(yīng)的RpcStatus的active加一。

代碼@8:執(zhí)行RPC服務(wù)調(diào)用。

代碼@9:記錄成功調(diào)用或失敗調(diào)用,并將active減一。

代碼@10:最終成功執(zhí)行,如果開啟了actives機制(dubbo:referecnce actives=”“)時,喚醒等待者。

總結(jié):< dubbo:reference actives=”“/> 是控制消費端對 單個服務(wù)提供者單個服務(wù)允許調(diào)用的最大并發(fā)度。該值的取值不應(yīng)該大于< dubbo:service executes=”“/>的值,并且如果消費者機器的配置,如果性能不盡相同,不建議對該值進行設(shè)置。