服務呼叫擴展點

本文將介紹如何在 Dubbo 3 中自訂呼叫鏈路上的核心擴展點,以滿足您的需求。

dubbo-architecture

如上圖所示,從服務呼叫的角度來看,Dubbo 在鏈路中提供了豐富的擴展點,涵蓋負載均衡方式、選址前後的攔截器、伺服器端處理攔截器等。簡單來說,當 Dubbo 發起遠端呼叫時,主要的工作流程可以分為消費者端和伺服器端兩部分。

消費者端的工作流程如下

  • 透過 Stub 接收使用者請求,並封裝成 Invocation 物件
  • Invocation 物件傳遞給 ClusterFilter (擴展點),進行選址前的請求預處理,例如請求參數的轉換、請求日誌記錄、電流限制等操作都在此階段進行
  • Invocation 物件傳遞給 Cluster (擴展點),進行叢集呼叫邏輯的決策,例如快速失敗模式、安全失敗模式等決策都在此階段進行
    • Cluster 呼叫 Directory 獲取所有可用的伺服器地址資訊
    • Directory 呼叫 StateRouter (擴展點,推薦) 和 Router (擴展點) 對伺服器的地址資訊進行過濾,此階段主要是從全量的地址資訊中過濾出本次呼叫允許呼叫的目標,例如基於標籤的流量路由就在此階段進行
    • Cluster 獲取到 Directory 提供的可用的伺服器資訊後,會呼叫 LoadBalance (擴展點) 從多個地址中選擇一個本次呼叫的目標,例如隨機呼叫、輪詢呼叫、一致性雜湊等策略都在此階段進行
    • Cluster 會取得目標的 Invoker,然後將 Invocation 傳遞給對應的 Invoker,並等待結果返回,如果發生錯誤(例如快速失敗、安全失敗等),則執行相應的決策。
  • 經過上述處理,取得帶有目標地址信息的 Invoker 後,會調用 Filter擴展點)對請求進行地址選取後的處理(由於消費者端創建的 Filter 數量級與服務器地址相同,如果沒有特殊需要,建議使用 ClusterFilter 進行擴展攔截,提升性能)。
  • 最後 Invocation 會通過網絡發送給服務器。

服務器的處理流程如下:

  • 服務器通信層接收到請求後,會將請求傳遞給協議層,構建 Invocation
  • Invocation 對象傳遞給 Filter擴展點)進行服務器請求的前置處理,例如服務器身份驗證、日誌記錄、限流等操作都在此階段執行。
  • Invocation 對象傳遞給動態代理,進行真正的服務器調用。

Filter (攔截器)

攔截器可以實現對服務提供者和服務消費者調用過程的攔截,Dubbo 自身的大部分功能都是基於此擴展點實現的,每次遠程方法執行都會執行攔截,請注意對性能的影響。其中,在消費者端,ClusterFilter 用於地址選取前的攔截,Filter 用於地址選取後的攔截,如果沒有特殊需要,使用 ClusterFilter 進行擴展攔截,提升性能。

filter-architecture

在 Dubbo 3 中,FilterClusterFilter 的接口簽名被統一抽象成 BaseFilter,開發者可以分別實現 FilterClusterFilter 的接口來實現自己的攔截器。如果需要攔截返回狀態,可以直接實現 BaseFilter.Listener 接口,Dubbo 會自動識別並調用。

package org.apache.dubbo.rpc;

public interface BaseFilter {
    
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;

    interface Listener {

        void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);

        void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
    }
}
package org.apache.dubbo.rpc;

@SPI(scope = ExtensionScope. MODULE)
public interface Filter extends BaseFilter {
}
package org.apache.dubbo.rpc.cluster.filter;

@SPI(scope = ExtensionScope. MODULE)
public interface ClusterFilter extends BaseFilter {
}

特別地,如果 FilterClusterFilter 需要在 Consumer 端生效,需要加上 @Activate 註解,且 group 的值需要為 consumer

@Activate(group = CommonConstants. CONSUMER)

如果 FilterClusterFilter 需要在 Provider 端生效,需要加上 @Activate 註解,且 group 的值需要為 provider

@Activate(group = CommonConstants. PROVIDER)

具體調用攔截擴展方式請參考參考文件

Router (路由地址選取)

路由地址選取提供從多個服務提供者中選取一批符合條件的目標提供者進行調用的能力。Dubbo 的路由主要需要實現 3 個接口,分別是負責每次調用篩選的 route 方法,地址推送後負責緩存的 notify 方法,以及銷毀路由的 stop 方法。建議在 Dubbo 3 中實現 StateRouter 接口,可以提供高性能的路由地址選取。

package org.apache.dubbo.rpc.cluster.router.state;

public interface StateRouter<T> {

    BitList<Invoker<T>> route(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
                     boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder) throws RpcException;

    void notify(BitList<Invoker<T>> invokers);

    void stop();
}
package org.apache.dubbo.rpc.cluster;

public interface Router extends Comparable<Router> {

    @Deprecated
    List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
    
    <T> RouterResult<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation,
                                                     boolean needToPrintMessage) throws RpcException;

    <T> void notify(List<Invoker<T>> invokers);

    void stop();
}

具體路由地址選取擴展方式請參考參考文件

Cluster (集群規則)

集群規則提供在有多個服務提供者時,進行結果聚合、故障容錯等能力。

package org.apache.dubbo.rpc.cluster.support;

public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
    
    protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
                                       LoadBalance loadbalance) throws RpcException;
}

具體集群規則擴展方式請參考參考文件

LoadBalance (負載均衡)

負載均衡提供從多個服務提供者中選取**一個**目標提供者進行調用的能力。

package org.apache.dubbo.rpc.cluster;

public interface LoadBalance {
    
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}

具體調用攔截擴展方式請參考參考文件


最後修改日期:2023 年 1 月 2 日:增強英文文件 (#1798) (95a9f4f6c1c)