服务调用扩展点

本文将介绍如何在 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 对象传递给动态代理,进行真实的服务调用

过滤器(拦截器)

拦截器可以实现对服务提供者和服务消费者的调用过程进行拦截。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)

具体调用拦截扩展方法请参考 参考

路由器(路由地址选择)

路由地址选择提供从多个服务提供者中选择满足条件的一批目标提供者进行调用的能力。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();
}

有关特定路由地址选择扩展方法,请参考 参考

集群 (集群规则)

集群规则在存在多个服务提供者时,提供诸如结果聚合和容错等功能。

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;
}

有关特定集群规则扩展方法,请参考 参考

负载均衡

负载均衡提供从多个服务提供者中选择 **一个** 目标提供者进行调用的功能。

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 日:增强 en 文档 (#1798) (95a9f4f6c1c)