Dubbo核心模型之Invoker

Dubbo中invoker是provider和consumer实现RPC调用的关键,invoker的构建过程是Dubbo服务的init初始化过程。invoker#invoke的调用是Dubbo服务的call调用过程。因此,这里分析invoker模型,主要是provider和consumer端的初始化过程。

dubbo中常用的Invoker类,如下:

  • AbstractProxyInvoker:本地执行类的Invoker,实际通过Java反射的方式执行原始对象的方法。一般通过接口ProxyFactory的扩展类StubProxyFactoryWrapper、JavassistProxyFactory先后执行完成目标接口的代理。
  • AbstractInvoker:远程通信类的Invoker,实际通过通信协议发起远程调用请求,并接收响应。
  • AbstractClusterInvoker:多个远程通信类的Invoker聚合成的集群Invoker,加入了集群容错和负载均衡策略。cluster集群下的Invoker实现,采用模板方法设计模式,abstract定义方法框架,具体方法实现由子类实现。

Invoker是Dubbo中实体类,rpc的server端服务提供和client端服务调用,都要由invoker实现。因此,其作为一个可执行体,在server端,用于调用provider的本地服务调用;在client端,其内包含远程通信的NettyClient,用于远程调用。provider端和consumer端,在Config配置类中,分别持有ProxyFactory和Protocol实例。


1.ProxyFactory

该接口的作用:利用目标接口以及目标接口的实现类生成Invoker【服务提供端Invoker】;利用Invoker生成其代理对象。

@SPI(value = "javassist", scope = FRAMEWORK)
public interface ProxyFactory {

    @Adaptive({PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    @Adaptive({PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;

    /**
     * create invoker.
     * @param <T>
     * @param proxy 目标接口的具体实现类之ChinaServiceImpl
     * @param type 目标接口之CountryService
     * @param url
     * @return invoker
     */
    @Adaptive({PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}

当前接口涉及扩展类如下所示:

stub=org.apache.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory
nativestub=org.apache.dubbo.rpc.stub.StubProxyFactory

其中,StubProxyFactory适用于生成非反射方式的invoker、proxy,主要依赖于Dubbo3 Triple协议。正常调用方向:StubProxyFactoryWrapper -> JavassistProxyFactory。


2.Protocol

@SPI(value = "dubbo", scope = ExtensionScope.FRAMEWORK)
public interface Protocol {

    /**
     * 提供端导出服务方便消费端远程调用:
     * 1. 服务提供端接收到远程访问后需要记录消费端IP地址等信息:RpcContext.getServerAttachment().setRemoteAddress()。
     * 2. 服务导出功能必须是idempotent幂等的,there's no difference between invoking once and invoking twice when export the same URL。
     * 3. Invoker instance is passed in by the framework, protocol needs not to care。
     *
     * @param <T>     Service type
     * @param invoker Service invoker
     * @return exporter reference for exported service, useful for unexport the service later
     * @throws RpcException thrown when error occurs during export the service, for example: port is occupied
     */
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    /**
     * 消费端引用远程服务: 
     * 1. 消费端通过Invoker#invoke调用refer指定的远程服务时,the protocol needs to correspondingly execute `invoke()` method of `Invoker` object。
     * 2. It's protocol's responsibility to implement `Invoker` which's returned from `refer()`. Generally speaking,
     * protocol sends remote request in the `Invoker` implementation. <br>
     * 3. When there's check=false set in URL, the implementation must not throw exception but try to recover when connection fails.
     * @param <T>  Service type
     * @param type Service class
     * @param url  URL address for the remote service
     * @return invoker service's local proxy
     * @throws RpcException when there's any error while connecting to the service provider
     */
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
}

当前接口涉及扩展类如下所示: 

filter=org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
serializationwrapper=org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper
 
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol
tri=org.apache.dubbo.rpc.protocol.tri.TripleProtocol
registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol
service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper

 ProtocolSerializationWrapper->ProtocolFilterWrapper->ProtocolListenerWrapper->QosProtocolWrapper->RegistryProtocol


3.消费端Invoker

Consumer端之Invoker用于执行远程调用(所以consumer端invoker带有通信能力,内部传入NettyClient)。

public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
    private T createProxy(Map<String, String> referenceParameters) {
        ...
        createInvokerForRemote();
        ...
        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }
}
  1. 制造一个远程reference,创造一个远程reference Invoker。
  2. 基于 Invoker 生成目标接口的代理。

3.1. reference & reference Invoker

RegistryProtocol生成最初Invoker之MigrationInvoker,并通过RegistryProtocolListener控制Invoker的状态和行为。直观点其实就是属性invoker、serviceDiscoveryInvoker的赋值操作。

public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {

    private URL url;
    private URL consumerUrl;
    private Cluster cluster;
    private Registry registry;
    private Class<T> type;
    private RegistryProtocol registryProtocol;
    private MigrationRuleListener migrationRuleListener;

    private volatile ClusterInvoker<T> invoker;
    private volatile ClusterInvoker<T> serviceDiscoveryInvoker;
    private volatile ClusterInvoker<T> currentAvailableInvoker;
}

此时MigrationInvoker内部相关属性如下所示:

RegistryProtocolListener内部通过MigrationRuleHandler基于MigrationRule规则Migrate改变Invoker的状态和行为。

public class MigrationRuleHandler<T> {
    // MigrationInvoker
    private MigrationClusterInvoker<T> migrationInvoker;
    private URL consumerURL;
    public MigrationRuleHandler(MigrationClusterInvoker<T> invoker, URL url) {
        this.migrationInvoker = invoker;
        this.consumerURL = url;
    }
    public synchronized void doMigrate(MigrationRule rule) {
        ....
        if (refreshInvoker(step, threshold, rule)) {
            setMigrationRule(rule);
        }
    }
    
    private boolean refreshInvoker(MigrationStep step, Float threshold, MigrationRule newRule) {
        MigrationStep originStep = currentStep;
        if ((currentStep == null || currentStep != step) || !currentThreshold.equals(threshold)) {
            boolean success = true;
            switch (step) {
                case APPLICATION_FIRST://默认执行策略
                    migrationInvoker.migrateToApplicationFirstInvoker(newRule);
                    break;
                case FORCE_APPLICATION:
                    success = migrationInvoker.migrateToForceApplicationInvoker(newRule);
                    break;
                case FORCE_INTERFACE:
                default:
                    success = migrationInvoker.migrateToForceInterfaceInvoker(newRule);
            }
            ...
            return success;
        }
        return true;
    }
}
public class MigrationInvoker<T> implements MigrationClusterInvoker<T> {
    private RegistryProtocol registryProtocol;
    private volatile ClusterInvoker<T> invoker;
    private volatile ClusterInvoker<T> serviceDiscoveryInvoker;

    public void migrateToApplicationFirstInvoker(MigrationRule newRule) {
        CountDownLatch latch = new CountDownLatch(0);
        //初始化参数invoker
        refreshInterfaceInvoker(latch);
        //初始化参数serviceDiscoveryInvoker
        efreshServiceDiscoveryInvoker(latch);
        calcPreferredInvoker(newRule);
    }  
     
    protected void refreshServiceDiscoveryInvoker(CountDownLatch latch) {
        serviceDiscoveryInvoker = registryProtocol.getServiceDiscoveryInvoker(cluster, registry, type, url);
    }

    protected void refreshInterfaceInvoker(CountDownLatch latch) {
        invoker = registryProtocol.getInvoker(cluster, registry, type, url);
    } 
}

截止当前才真正开始初始化MigrationInvoker内部相关属性invoker、serviceDiscoveryInvoker

3.2.MigrationInvoker之属性invoker

public class RegistryProtocol implements Protocol{
    protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
        ...
        //directory类型:RegistryDirectory
        if (directory.isShouldRegister()) {
            // 1.通过zkClient注册当前消费端服务
            directory.setRegisteredConsumerUrl(urlToRegistry);
            registry.register(directory.getRegisteredConsumerUrl());
        }
        directory.buildRouterChain(urlToRegistry);
        //2.当前消费端监听的节点
        directory.subscribe(toSubscribeUrl(urlToRegistry));
        //3.利用MockClusterWrapper创建Invoker
        return (ClusterInvoker<T>) cluster.join(directory, true);
    }
}

zk注册当前消费端服务:创建如下节点 

/dubbo/common.service.CountryService/consumers/consumer%3A%2F%2F192.168.80.36%2Fcommon.service.CountryService%3Fapplication%3Ddubbo-consumer%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26interface%3Dcommon.service.CountryService%26lazy%3Dtrue%26methods%3DgetCountry%26pid%3D65342%26qos.enable%3Dfalse%26register-mode%3Dinstance%26release%3D3.0.7%26revision%3D2.0%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1712909849973%26version%3D2.0

 在zk端创建以下节点,并添加相关zk监听器 :

/dubbo/common.service.CountryService/providers
/dubbo/common.service.CountryService/configurators
/dubbo/common.service.CountryService/routers

最终返回的Invoker:MockClusterInvoker -> AbstractCluster静态内部类AbstractClusterInvoker。当前在内部类AbstractClusterInvoker构造方法内部会初始化过滤器filter类型的ClusterInvoker。


3.2.MigrationInvoker之属性serviceDiscoveryInvoker

public class RegistryProtocol implements Protocol{
    protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
        ...
        // directory:ServiceDiscoveryRegistryDirectory
        if (directory.isShouldRegister()) {
            // 1.zkClient注册当前消费端服务已经完成,此处不会重复执行
            directory.setRegisteredConsumerUrl(urlToRegistry);
            registry.register(directory.getRegisteredConsumerUrl());
        }
        directory.buildRouterChain(urlToRegistry);
        //2.获取服务提供端对应的IP信息,提供消费端远程调用提供端接口
        directory.subscribe(toSubscribeUrl(urlToRegistry));
        //3.利用MockClusterWrapper创建Invoker
        return (ClusterInvoker<T>) cluster.join(directory, true);
    }
}

获取服务提供端地址信息后还涉及具有远程通信功能的DubboInvoker初始化

public class ServiceDiscoveryRegistry{
    protected void subscribeURLs(URL url, NotifyListener listener, Set<String> serviceNames) {
        serviceNames = toTreeSet(serviceNames);
        String serviceNamesKey = toStringKeys(serviceNames);
        String protocolServiceKey = url.getProtocolServiceKey();
        Lock appSubscriptionLock = getAppSubscription(serviceNamesKey);
        appSubscriptionLock.lock();
        ServiceInstancesChangedListener serviceInstancesChangedListener = serviceListeners.get(serviceNamesKey);
        if (serviceInstancesChangedListener == null) {
            serviceInstancesChangedListener = serviceDiscovery.createListener(serviceNames);
            serviceInstancesChangedListener.setUrl(url);
            for (String serviceName : serviceNames) {
                // 获取到 服务提供端服务 所有地址列表
                List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName);
                if (CollectionUtils.isNotEmpty(serviceInstances)) {
                    serviceInstancesChangedListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));
                }
            }
            serviceListeners.put(serviceNamesKey, serviceInstancesChangedListener);
        }

        if (!serviceInstancesChangedListener.isDestroyed()) {
            serviceInstancesChangedListener.setUrl(url);
            listener.addServiceListener(serviceInstancesChangedListener);
            // 基于提供端服务列表生成与之对应的DubboInvoker
            serviceInstancesChangedListener.addListenerAndNotify(protocolServiceKey, listener);
            serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener);
        } else {
            logger.info(String.format("Listener of %s has been destroyed by another thread.", serviceNamesKey));
            serviceListeners.remove(serviceNamesKey);
        }
    }
}

返回的serviceDiscoveryInvoker属性:MockClusterInvoker -> AbstractCluster静态内部类AbstractClusterInvoker。此时AbstractClusterInvoker内部由ServiceDiscoveryRegistryDirectory加载的过滤器filter类型的ClusterInvoker区别于MigrationInvoker属性invoker。


3六Dubbo核心技术归纳--3Dubbo中Invoker的作用及转换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值