• dubbo Protocol实现剖析



    title: dubbo Protocol实现剖析
    date: 2018-09-09 19:10:07
    tags:

    2.6.3版本,之前读的是2.4.9版本
    本篇主要阐述dubbo rpc的com.alibaba.dubbo.rpc.Protocol的实现,包括作用,用法,原理等等。

    类与接口关系以及其装配

    根据类与接口关系文档可以看到Protocol实现关系如下:
    264 Protocol
    --264.1 QosProtocolWrapper
    --264.2 RegistryProtocol
    --264.3 AbstractProtocol
    ----264.3.1 AbstractProxyProtocol
    ------264.3.1.1 HessianProtocol
    ------264.3.1.2 HttpProtocol
    ------264.3.1.3 RestProtocol
    ------264.3.1.4 RmiProtocol
    ------264.3.1.5 WebServiceProtocol
    ----264.3.2 DubboProtocol
    ----264.3.3 InjvmProtocol
    ----264.3.4 MemcachedProtocol
    ----264.3.5 RedisProtocol
    ----264.3.6 ThriftProtocol
    ----264.3.7 MockProtocol
    --264.4 InjvmProtocol
    --264.5 ProtocolFilterWrapper
    --264.6 ProtocolListenerWrapper
    默认会用到 QosProtocolWrapper RegistryProtocol(如果有注册中心) DubboProtocol InjvmProtocol ProtocolFilterWrapper ProtocolListenerWrapper。

    在META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol中做了装配
    filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
    listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
    mock=com.alibaba.dubbo.rpc.support.MockProtocol
    dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
    injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
    rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
    hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
    com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
    com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
    thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
    memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
    redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
    rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol
    registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
    qos=com.alibaba.dubbo.qos.protocol.QosProtocolWrapper

    扩展点机制createAdaptiveExtensionClass

    要看懂protocol的实例化与export过程最好先了解下扩展点机制,前面有文章写过。 此处要需要注意ExtensionLoader类的下面代码:

    private Class<?> createAdaptiveExtensionClass() {
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }
    

    再协议初始化与export时会动态生成的两个类的代码: Protocol$Adaptive,ProxyFactory$Adaptive,看上面code变量就是生成的具体代码了。

    protocol及其wrap之间的关系

    在扩展点机制com.alibaba.dubbo.common.extension.ExtensionLoader.createExtension(String)中:
    在创建扩展实例时,会同时对他的wrap类的实例进行创建,代码细节如下:

    T instance = (T) EXTENSION_INSTANCES.get(clazz);
    if (instance == null) {
        EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
        instance = (T) EXTENSION_INSTANCES.get(clazz);
    }
    injectExtension(instance);// 此时是DubboProtocol示例
    Set<Class<?>> wrapperClasses = cachedWrapperClasses;
    if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
        for (Class<?> wrapperClass : wrapperClasses) {
            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));// 此处创建wrap实例
        }
    }
    

    实际应用中,以dubbo协议这个扩展为例,当创上述代码建了DubboProtocol协议的instance,此时是DubboProtocol实例,接下来对cachedWrapperClasses进行for循环,创建对应的wrap类,这些wrap类都有一个以Protocol类型的参数,那么创建wrap实例的时候,会把之前产生的Protocol实例传递给他。
    此例,cachedWrapperClasses里的数据来自于META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件中配置的是wrap的扩展,
    此处是:
    class com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
    class com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,
    class com.alibaba.dubbo.qos.protocol.QosProtocolWrapper,
    (怎么从配置文件中识别是否是wrap类?答案是 只要这个QosProtocolWrapper类有类型为Protocol的构造函数存在,就当QosProtocolWrapper是wrap类。)
    那么此处便会依次构造这三个类。 这个三个类的构造顺序不固定,因为用的上面createExtension代码中cachedWrapperClasses是ConcurrentHashSet维护的。

    export机制

    整体构造与export顺序即触发时机的解释

    此处是以provider端为例
    DubboProtocol.() line: 162 // final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); ServiceConfig取默认端口值 ,用在没有对dubbo:protocol标签配置端口时

    ProtocolListenerWrapper.(Protocol) line: 41 // 上面实例化DubboProtocol实例时,会级联实例化其关联的wrap类,级联的wrap类是怎么获取的 参见级联的wrap类是怎么获取部分
    QosProtocolWrapper.(Protocol) line: 39 // 上面实例化DubboProtocol实例时,会级联实例化其关联的wrap类
    ProtocolFilterWrapper.(Protocol) line: 40 // 上面实例化DubboProtocol实例时,会级联实例化其关联的wrap类

    ProtocolListenerWrapper.(Protocol) line: 41 // ServiceConfig 对本端需要暴露的服务 做exportLocal(url) 时,会export injvm协议,那么这时又会级联实例化 其关联的wrap类,同样是3个 :
    QosProtocolWrapper.(Protocol) line: 39 // ServiceConfig 做exportLocal(url) 时,会export injvm协议,级联实例化,同上
    ProtocolFilterWrapper.(Protocol) line: 40 // ServiceConfig 做exportLocal(url) 时,会export injvm协议,级联实例化,同上

    ProtocolFilterWrapper.export(Invoker) line: 97 // 对上面做exportLocal时级联创建出来的wrap类调用export方法 ,而这三个wrap类又会对他内部的protocol做export调用 就是下面这几个
    QosProtocolWrapper.export(Invoker) line: 52 // 被上行这个级联export的
    ProtocolListenerWrapper.export(Invoker) line: 54 // 被上行这个级联export的
    InjvmProtocol.export(Invoker) line: 86 // 被上行这个级联export的 结果是创建一个InjvmExporter实例, 也即是说export可能是调自己级联的protocol,也可能是创建一个exporter

    RegistryProtocol.() line: 73
    //

    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
    
    Exporter<?> exporter = protocol.export(wrapperInvoker);
    

    针对 registryURL 先创建invoker,再用这个invoker创建wrapperInvoker,再用wrapperInvoker做exporter。

    ProtocolListenerWrapper.(Protocol) line: 41 // 被RegistryProtocol级联创建
    QosProtocolWrapper.(Protocol) line: 39 // 被RegistryProtocol级联创建
    ProtocolFilterWrapper.(Protocol) line: 40 // 被RegistryProtocol级联创建

    ProtocolFilterWrapper.export(Invoker) line: 97 // RegistryProtocol做export时先级联的wrap实例进行export 这三个wrap中 对REGISTRY_PROTOCOL做了特殊逻辑处理。 详细请参见代码
    QosProtocolWrapper.export(Invoker) line: 52 // 同上
    ProtocolListenerWrapper.export(Invoker) line: 54 // 同上
    RegistryProtocol.export(Invoker) line: 132 // 同上 最终export出了DestroyableExporter 就是对应Registry协议的exporter
    ProtocolFilterWrapper.export(Invoker) line: 97 // 上行RegistryProtocol export时先做doLocalExport,doLocalExport时把provider的url与其对应的exporter做一个缓存(如果缓存中没有,此时要export,并把对provider export出来的结果做ExporterChangeableWrapper的包装,最后返回ExporterChangeableWrapper实例。这行的这个export就是被这个触发的,详细的可以参见他代码)

    String key = getCacheKey(originInvoker);
    ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
    if (exporter == null) {
        synchronized (bounds) {
            exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
            if (exporter == null) {
                final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                bounds.put(key, exporter);
            }
        }
    }
    

    QosProtocolWrapper.export(Invoker) line: 52 // 上一行级联触发
    ProtocolListenerWrapper.export(Invoker) line: 54 // 上上一行级联触发
    DubboProtocol.export(Invoker) line: 229 // 上上上一行级联触发

    ProtocolFilterWrapper

    rpc过滤器链的组织创建者。

    如果是注册中心 级联export的,直接级联wrap的protocol进行export,不做其他处理。
    如果是非注册中心 级联export的,比如injvm dubbo这种协议级联的,做buildInvokerChain 构建调用中过滤器链的处理。 就是前面博客介绍的rpc过滤器com.alibaba.dubbo.rpc.Filter的实现实例串起来。通过循环加内部类访问外围变量的方式组成的链。贴下关键代码:

    for (int i = filters.size() - 1; i >= 0; i--) {
        final Filter filter = filters.get(i);
        final Invoker<T> next = last;
        last = new Invoker<T>() {
    // ......
            public Result invoke(Invocation invocation) throws RpcException {
                return filter.invoke(next, invocation);
            }
    // ......
        };
    }
    

    next与last配合使用形成了链。

    QosProtocolWrapper

    如果是非注册中心 级联export的,直接级联wrap的protocol进行export,不做其他处理
    如果是注册中心 级联export的,启动QoS server。参见com.alibaba.dubbo.qos.server.Server。

    ProtocolListenerWrapper

    用于服务export时候监听机制的插入。

    如果是注册中心 级联export的,直接级联wrap的protocol进行export,不做其他处理。
    如果是非注册中心 级联export的,比如injvm dubbo这种协议级联的,先级联wrap的protocol进行export,再创建ListenerExporterWrapper实例。 主要是为了让ExporterListener监听器插入进来。

    RegistryProtocol

    对应注册中心协议

    先做本地的export
    然后根据配置将 registry://127.0.0.1:2174/com.alibaba.dubbo.registry.RegistryService?application=hello-...置换成具体的注册中心协议地址,如: zookeeper://127.0.0.1:2174/com.alibaba.dubbo.registry.RegistryService?application=hello-world-...
    根据注册中心协议地址 或者Registry-->ZookeeperRegistry的实例。
    判断是否是非延迟暴露的,就开始注册,比较简单:

    zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
    

    可以通过其父类FailbackRegistry看到,支持失败重试,由一个定时调度线程重试。

    this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {
        @Override
        public void run() {
            // Check and connect to the registry
            try {
                retry();
            } catch (Throwable t) { // Defensive fault tolerance
                logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
            }
        }
    }, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
    

    Failback是一种容错,详细的可以参见 常见容错机制。
    注册之后是对OverrideListener 的处理。
    该export返回的是DestroyableExporter实例,顾名思义是可以销毁的exoprter,在其unexport里做了文章,移除注册,移除export。

    ref机制

    先看下consumer端发起调用时的链路流程:

     +---------------------------+            +---------------------------+            +---------------------------+              
     |      helloService         |            |      proxy                |            |  InvokerInvocationHandler |              
     |      sayHello             +----------> |      sayHello             +----------> |  invoke                   |              
     |                           |            |                           |            |  proxy method args        |              
     +---------------------------+            +---------------------------+            +-------------+-------------+              
                                                                                                     |                            
                                                                                                     |                            
                                                                                      +---------------------------------+         
                                                                                      |              |                  |         
                                                                                      | +------------v--------------+   |         
                                                                                      | |  MockClusterInvoker       |   |         
                                                                                      | |  invoke                   |   |         
                                                                                      | |                           |   |         
                                                                                      | +------------+--------------+   |         
                                                                                      |              |                  |         
                                                                                      |              |                  |         
                                                                                      |              |                  |         
     +---------------------------+            +---------------------------+           | +------------v--------------+   |         
     | Router                    |            | RegistryDirectory         |           | |  FailoverClusterInvoker   |   |         
     | route                     | <----------+ list                      | <-----------+  invoke                   |   |         
     | MockInVokersSelector      |            | INVOCATION-->List INVOKER |           | |                           |   |         
     +------------+--------------+            +---------------------------+           | +---------------------------+   |         
                  |                                                                   |                                 |         
                  |                                                                   +---------------------------------+         
                  |                                                                 cluster invoke,分布式调用容错机制也是在这做                      
                  |                                                                                                               
                  |                                                                                                               
                  |                                                                                                               
                  |                                                                                                               
                  |                                                                                                               
    +-------------v-------------+             +---------------------------+             +---------------------------+             
    |  RandomLoadBalance        |             |InvokerDelegate            |             | ListenerInvokerWrap       |             
    |  select                   +-----------> |invoke                     +-----------> | invoke                    |             
    |  List INVOKER-->INVOKER   |             |                           |             |                           |             
    +---------------------------+             +---------------------------+             +---------------------------+             
    
    

    RegistryProtocol 注册中心协议 对接口协议接口约束,不论何种注册中心都走这个实现。
    RegistryDirectory 提供由服务目录查找出真正能提供服务的所有提供方
    Registry 各个注册中心的实现的接口约束,具体实现有 RedisRegistry ZookeeperRegistry MulticastRegistry DubboRegistry。 主要完成注册这个逻辑。 就是把自己的信息写入注册中心。
    Cluster 多服务提供方的一个封装 。他们负责创建多服务调用者实例。 比如FailoverCluster负责创建FailoverClusterInvoker实例。Cluster的实现是以分布式容错机制Failover,Failfast,Failback等这些维度进行。 对应invoker也是按照这个维度划分,比如FailbackClusterInvoker,FailfastClusterInvoker,BroadcastClusterInvoker等等。
    Router 路由机制
    LoadBalance 负载均衡机制
    Invoker 调用者。 按分布式容错机制的维度进行划分了多个实现,与 Cluster实现一一对应。
    基本上描述了 由consumer的ref类-->proxy-->InvokerInvocationHandler-->clusterinvoker-->服务目录查找-->路由机制-->负载均衡机制-->调用委托-->调用监听器。

    Invoker的实现结构:
    --61.1 Invoker
    ----61.1.1 DelegateProviderMetaDataInvoker
    ----61.1.2 ConsumerInvokerWrapper
    ----61.1.3 ProviderInvokerWrapper
    ----61.1.4 AbstractClusterInvoker
    ------61.1.4.1 AvailableClusterInvoker
    ------61.1.4.2 BroadcastClusterInvoker
    ------61.1.4.3 FailbackClusterInvoker
    ------61.1.4.4 FailfastClusterInvoker
    ------61.1.4.5 FailoverClusterInvoker
    ------61.1.4.6 FailsafeClusterInvoker
    ------61.1.4.7 ForkingClusterInvoker
    ----61.1.5 MergeableClusterInvoker
    ----61.1.6 MockClusterInvoker
    ----61.1.7 ListenerInvokerWrapper
    ----61.1.8 AbstractInvoker
    ------61.1.8.1 ChannelWrappedInvoker
    ------61.1.8.2 DubboInvoker
    ------61.1.8.3 InjvmInvoker
    ------61.1.8.4 ThriftInvoker
    ----61.1.9 InvokerWrapper
    ----61.1.10 AbstractProxyInvoker
    ----61.1.11 DelegateInvoker
    ----61.1.12 MockInvoker

    RegistryProtocol

    ref完成的逻辑是:
    创建服务目录实例 RegistryDirectory
    创建ClusterInvoker,默认是FailoverClusterInvoker..

    其他

    ProtocolFilterWrapper, QosProtocolWrapper, ProtocolListenerWrapper的ref逻辑与export基本相同,不再赘述。

  • 相关阅读:
    matlab简单线性规划&单纯形法
    matlab多变量绘图函数(类似ggplot2)
    matlab近似泛函优化
    如何求矩阵的逆矩阵
    数值分析手写笔记
    latex绘图小结
    数理统计手写笔记
    matlab kriging模型
    运筹学与最优化手写笔记
    matlab既约梯度法习题
  • 原文地址:https://www.cnblogs.com/simoncook/p/9614660.html
Copyright © 2020-2023  润新知