Dubbo——消費者過濾器的實現原理

ActiveLimitFilter的實現原理

和服務提供者端的ExecuteLimitFilter相似,ActiveLimitFilter是消費者端的過濾器,顯示的是客戶端的併發數。

<!-- 限制com.foo.BarService的每個方法在每個客戶端的併發執行數(或佔用連接的請求數)不能超過10個 -->
<dubbo:service interface="com.foo.BarService" actives="10" /><dubbo:reference interface="com.foo.BarService" actives="10" />

<!-- 限制com.foo.BarService的sayHello方法在每個客戶端的併發執行數(或佔用連接的請求數)不能超過10個 -->
<dubbo:service interface="com.foo.BarService" >
	<dubbo:method name="sayHello" actives="10" />
</dubbo:service><dubbo:reference interface="com.foo.BarService" >
	<dubbo:method name="sayHello" actives="10" />
</dubbo:reference>

如果<dubbo:service>和<dubbo:reference>都配置了actives,則<dubbo:reference>優先。如果設置了acties小於等於0,則不作併發限制。

ActiveLimitFilter的具體實現邏輯:

  1. 獲取參數。獲取方法名、最大併發數等參數,爲下面邏輯做準備。
  2. 如果達到限流閾值,和服務提供者端的邏輯並不一樣,並不是直接拋出異常,而是先等待直到超時,因爲請求是有timeout屬性的。當併發數達到閾值時,會先加鎖搶佔當前解耦的RpcStatus對象,然後通過wait方法進行等待。此時會有兩種結果:
    1. 第一種是某個Invoker在調用結束後,併發把計數器原子-1並處罰一個norify,會有一個在wait狀態的線程被喚醒並繼續執行邏輯。
    2. 第二種是wait等待超時都沒有被喚醒,此時直接拋出異常

在這裏插入圖片描述
在這裏插入圖片描述
3. 如果滿足調用閾值,則直接進行調用,成功或失敗都會原子-1對應併發計數。最後會喚醒一個等待中的線程。

注意:這種方式限流是有問題的,在大併發場景下容易出現超時限流閾值的情況。例如:當10個線程同時獲取當前併發數時,都發現還差1個計數達到閾值,此時10個線程都符合要求並往下執行,即超了9個限制。不過該問題在新版本中已經修復。

ConsumerContextFilter的實現原理

ConsumerContextFilter會和ContextFilter配合使用。因爲在微服務環境中,有很多鏈式調用,如A->B->C->D。收到請求時,當前節點可以被看做一個服務提供者,由ContextFilter設置上下文。當發起請求到下一個服務時,當前服務變爲一個消費者,由ConsumerContextFilter設置上下文。

其工作邏輯主要如下:

  1. 設置當前請求上下文,如Invoker信息、地址信息、端口信息等;
  2. 服務調用。清除Response上下文,然後繼續調用過濾器鏈的下一個節點;
  3. 清除上下文信息。每次服務調動完成,都會把附件上下文清除,如隱式傳參。

DeprecatedFilter的實現原理

DEprecatedFilter會檢查所有調用,如果方法已經通過dubbo:parameter設置了deprecated=true,則會打印一段ERROR級別的日誌。這個錯誤日誌只會打印一次,判斷是否打印過的key維度是:接口名+方法名。打印過的key都會加入一個Set中保存,後續就不會再打印了:

在這裏插入圖片描述

FutureFilter的實現原理

FutureFilter主要實現框架在調用前後出現異常時,觸發調用胡勇配置的回調方法,如以下配置:

<!-- 用戶編寫的回調方法,裏面又onreturn、onthrow、oninvoke幾個方法 -->
<bean id="callBack" class="com.test.CallBack" />

<!-- 在testMethod的調用前後出現異常時,分別調用回調類的方法 -->
<dubbo:reference id="testService" interface="com.testService">
	<dubbo:method name="testMetho" onreturn="callBack.onreturn" onthrow="callBack.onthrow" oninvoke="callBack.oninvoke" />
</dubbo:reference>

調用前的回調實現很簡單,由於整個邏輯是在過濾器鏈中執行的,FutureFilter在執行下一個節點的invoke方法前調用oninvoke回調方法就能實現調用前的回調。方法在服務引用初始化的時候就會配置文件中的回調方法保存到ConsumerMethodModel中,後續使用的時候,直接取出來就可以調用。不過需要注意的是,oninvke回調只對異步調用有效。

當調用有返回結果的時候,會執行FutureFilter#onResponse的邏輯。對於同步調用的方法,則直接判斷返回的result是否有異常,有異常則同步調用ontrow回調方法,沒有異常則同步調用onreturn回調方法。對於異步調用,會通過CompletableFuture的thenApply方法來執行onthrow或onreturn的回調。CompletableFuture是JDK8中的新特性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章