精华内容
下载资源
问答
  • dubbo原理和机制

    千次阅读 2020-05-03 15:19:20
    Dubbo 框架是用来处理分布式系统中,服务发现与注册以及调用问题的,并且管理调用过程。 一,工作流程: ...Proxy 在封装时,需要调用 Protocol 定义协议格式,例如:Dubbo Protocol。 将 Proxy ...

    Dubbo 框架是用来处理分布式系统中,服务发现与注册以及调用问题的,并且管理调用过程。
    一,工作流程:
    在这里插入图片描述

    • 服务提供者在启动的时候,会通过读取一些配置将服务实例化。
    • Proxy 封装服务调用接口,方便调用者调用。客户端获取 Proxy 时,可以像调用本地服务一样,调用远程服务。
    • Proxy 在封装时,需要调用 Protocol 定义协议格式,例如:Dubbo Protocol。
    • 将 Proxy 封装成 Invoker,它是真实服务调用的实例。
    • 将 Invoker 转化成 Exporter,Exporter 只是把 Invoker
      包装了一层,是为了在注册中心中暴露自己,方便消费者使用。
    • 将包装好的 Exporter 注册到注册中心。
    • 服务消费者建立好实例,会到服务注册中心订阅服务提供者的元数据。元数据包括服务 IP 和端口以及调用方式(Proxy)。
    • 消费者会通过获取的 Proxy 进行调用。通过服务提供方包装过程可以知道,Proxy 实际包装了 Invoker 实体,因此需要使用
      Invoker 进行调用。
    • 在 Invoker 调用之前,通过 Directory 获取服务提供者的 Invoker
      列表。在分布式的服务中有可能出现同一个服务,分布在不同的节点上。
    • 通过路由规则了解,服务需要从哪些节点获取。
    • Invoker 调用过程中,通过 Cluster 进行容错,如果遇到失败策略进行重试。
    • 调用中,由于多个服务可能会分布到不同的节点,就要通过 LoadBalance 来实现负载均衡。
    • Invoker 调用之前还需要经过 Filter,它是一个过滤链,用来处理上下文,限流和计数的工作。
    • 生成过滤以后的 Invoker。
    • 用 Client 进行数据传输。
    • Codec 会根据 Protocol 定义的协议,进行协议的构造。
    • 构造完成的数据,通过序列化 Serialization 传输给服务提供者。
    • Request 已经到达了服务提供者,它会被分配到线程池(ThreadPool)中进行处理。
    • Server 拿到请求以后查找对应的 Exporter(包含有 Invoker)。
    • 由于 Export 也会被 Filter 层层包裹
    • 通过 Filter 以后获得 Invoker
    • 最后,对服务提供者实体进行调用。

    二、各个部分整体机制
    1、提供者暴露服务的整体机制:

    • 在服务提供者初始化的时候,会通过 Config 组件中的 ServiceConfig 读取服务的配置信息。这个配置信息有三种形式,分别是 XML 文件,注解(Annoation)和属性文件(Properties 和 yaml)。

    • 在读取配置文件生成服务实体以后,会通过 ProxyFactory 将 Proxy 转换成 Invoker。

    • 此时,Invoker 会被定义 Protocol,之后会被包装成 Exporter。

    • 最后,Exporter 会发送到注册中心,作为服务的注册信息

    2.注册中心
    其主要作用如下:

    • 动态载入服务
    • 动态发现服务
    • 参数动态调整
    • 服务统一配置管理

    在这里插入图片描述

    • 提供者(Provider)启动时,会向注册中心写入自己的元数据信息(调用方式)。
    • 消费者(Consumer)启动时,也会在注册中心写入自己的元数据信息,并且订阅服务提供者,路由和配置元数据的信息。
    • 服务治理中心(duubo-admin)启动时,会同时订阅所有消费者,提供者,路由和配置元数据的信息。
    • 当提供者离开或者新提供者加入时,注册中心发现变化会通知消费者和服务治理中心。

    Dubbo 有四种注册中心的实现,分别是 ZooKeeper,Redis,Simple 和 Multicast。
    ZooKeeper 是负责协调服务式应用的。通过树形文件存储的 ZNode 在 /dubbo/Service 目录下面建立了四个目录,分别是:

    Providers 目录下面,存放服务提供者 URL 和元数据。
    Consumers 目录下面,存放消费者的 URL 和元数据。
    Routers 目录下面,存放消费者的路由策略。
    Configurators 目录下面,存放多个用于服务提供者动态配置 URL 元数据信息。
    

    客户端第一次连接注册中心的时候,会获取全量的服务元数据,包括服务提供者和服务消费者以及路由和配置的信息。

    根据 ZooKeeper 客户端的特性,会在对应 ZNode 的目录上注册一个 Watcher,同时让客户端和注册中心保持 TCP 长连接。

    如果服务的元数据信息发生变化,客户端会接受到变更通知,然后去注册中心更新元数据信息。变更时根据 ZNode 节点中版本变化进行。

    3.服务消费者
    在这里插入图片描述
    服务消费者首先持有远程服务实例生成的 Invoker,然后把 Invoker 转换成用户接口的动态代理引用,服务引用的入口点在 ReferenceBean

    4.Dubbo 集群容错
    分布式服务多以集群形式出现,在消费服务发起调用的时候,会涉及到 Cluster,Directory,Router,LoadBalance 几个核心组件。
    在这里插入图片描述
    cluster生成 Invoker 对象后就获取可调用的服务列表,在 Directory 获取所有 Invoker 列表之后,会调用路由接口(Router)。其会根据用户配置的不同策略对 Invoker 列表进行过滤,只返回符合规则的 Invoker。生成的 Invoker服务有可能分布在不同的节点上面。所以,需要经过 LoadBalance。

    5.Dubbo 远程调用
    服务消费者经过容错,Invoker 列表,路由和负载均衡以后,会对 Invoker 进行过滤,之后通过 Client 编码,序列化发给服务提供者。

    展开全文
  • Dubbo 中,SPI 贯穿在整个Dubbo 的核心JAVA SPI在了解Dubbo 里面的SPI 之前,我们先了解下java 提供的SPI(service provider interface) 机制,SPI 是jdk 内置的一种服务提供发现机制。目前市面上有很多框架都是用...

    在Dubbo 中,SPI 贯穿在整个Dubbo 的核心

    JAVA SPI

    在了解Dubbo 里面的SPI 之前,我们先了解下java 提供的SPI(service provider interface) 机制,SPI 是jdk 内置的一种服务提供发现机制。目前市面上有很多框架都是用它来做服务的扩展发现。其实它是一种动态替换发现的机制。

    来张图辅助理解下

    12556113acaeaaff22708b35f2868431.png

    java SPI 的缺点

    JDK标准的SPI 会一次性加载实例化扩展点的所有实现,如果有些扩展点实现初始化很耗时那么会很浪费资源

    Dubbo 优化后的SPI 机制

    实现Dubbo SPI 扩展机制有两个规则

    1)需要在resource 目录下配置META-INF/dubbo 或者 META-INF/dubbo/internal 或者 META-INF/services,并基于 SPI 接口去 创建一个文件

    2)文件名称和接口名称保持一致,文件内容和 SPI有差异,内容是 KEY对应Value

    Dubbo 针对的扩展点非常多哦,可以针对协议、拦截、集群、路由等等几乎里面所有的功能,都可以实现自己的扩展

    01b7956d2a959f322e981058af103b71.png

    13701b45a54c0930feca09a5b69985f5.png

    ed922f77b7289dc88468b3607ee320d5.png

    输出的结果可以看到,是执行自定义的协议扩展点

    我们可以看下dubbo 包下的扩展

    91719a05a2ad7622f9438c78de496391.png

    思考:Dubbo 扩展点原理实现

    所谓扩展点,就是通过指定目录下配置一个对应接口的实现类,然后程序会查找解析,找到对应的扩展点

    怎么查找?怎么解析?

    我们来分析下源码,dubbo 源码版本是2.7.2

    2ec2cf2ca907ecc700b89f8605defab3.png

    0962fc588b459fff6f112252db6c1aab.png

    上图中的代码比较简单,接下来我们来看getExtension 方法

    c47e39860e8d70544ef03951dcf505cf.png

    接下来我们来看下createExtension 方法

    a66b88a0a744d328579bec270425add4.png

    f826c4881d261eb1e8f3bab4644762c8.png

    6c1020e067432e43b7bc58772e479ef2.png

    上图中可以看到我们自己的扩展类了,这种属于静态扩展点,比较简单,另外要了解一点,能够被扩展的接口,必须要有这样的标记:@SPI(),Dubbo 自定义的注解

    c8581131dad2aa488d7bdede58ce3d63.png

    2. 自适应扩展点(重要)

    什么是自适应扩展点?我们来看个例子,代码我贴出来

    9be425221c72328c2987f6910cf09877.png

    8fbc801f104035da8ff1f06a83a77598.png

    这是Compiler 扩展文件,可以看到打印出来的内容是在扩展文件第一个中,我们来看你这个类

    b2623ebe0f41f5e74027706e9a7039e2.png

    AdaptiveCompiler

    4f131c8ad97966a2d5d687299c4de405.png

    可以看到该类上有个@Adaptive 注解,该注解可以用到方法和类上,我们来看段代码

    a7bac795d97d08178ef903efb98f97b9.png

    这里的compile 会根据name 值来判断执行具体逻辑,从上面截图中我们可以看到@SPI("javassist") 这个注解的value,它来告诉我们默认走的哪个类

    我们来看下getDefaultExtension 方法

    42ca02c28a53f7c9f84222d4c5c2c533.png

    我们只需要来看getExtension(cachedDefaultName); 方法,它上面的的代码的我们都看过了;getExtension 方法是不是很熟悉,对的,它就是我们在main 方法里写的静态扩展代码

    6bf8c2a81d14ab586dacecb8e8ecd29f.png

    是不是有种贯通的感觉;好了我们来看下cachedDefaultName 在哪里赋值的

    003026eba6c513cb9f35ada36138f9ca.png

    这个属性的赋值本质上还是走的getExtension 方法指定的参数

    以上就是 @SPI 用在类上的内容,主要目的就是针对具体的实现进行适配

    我们来聊聊@SPI 用在方法上的作用

    fe0d60fce6cc1f68a67a610564945e0d.png

    结合图来理解下,我们平时配置协议时,可以指定Dubbo、WebService、Rest等那dubbo 内部是怎么找到指定协议执行的逻辑呢?看到下图我们可以得知Protocol 没有自适应扩展类,这个时候会动态的生成自适应扩展类,这就是@Apaptive用在方法上的作用

    e3dbcb9847c6712973c21ae10105acd0.png

    我们来看下ExtensionLoader 类的getAdaptiveExtension 方法,

    f602ce0a9bc4df8ef70e3ada89542821.png

    b984b15bf48292fb14ba2139cb30193c.png

    上图的code 就是动态生成扩展类的关键,生成的代码如下:

    10596615f218f5cd1b1d3fc18f2882a7.png

    根据extName 来判断具体走哪个扩展类,到这里核心的流程我们大致了解了,自适应扩展点在dubbo 中很重要,不了解这块的话看dubbo 源码会很懵圈

    多看两遍,多回顾两遍,多温习两遍

    展开全文
  • 2.Dubbo的SPI机制Dubbo实现插件式扩展的基础;而Dubbo中有一个重要的设计理念就是微内核、富插件模式。所谓的微内核、富插件就是内核提供特定的接口,而组件则只需要满足接口的特定要求就可以灵活的接入,并且管理...

    懂得Dubbo的同学一听到Dubbo肯定会有两个反应:1.Dubbo是高性能RPC调用的框架;2.Dubbo的SPI机制是Dubbo实现插件式扩展的基础;

    而Dubbo中有一个重要的设计理念就是微内核、富插件模式。所谓的微内核、富插件就是内核提供特定的接口,而组件则只需要满足接口的特定要求就可以灵活的接入,并且管理这些接入的插件,但是这些组件可以独立的发展、更改(不会对现有系统造成改动)。开发中常用的idea就有插件市场,还有像VSCode等,我们都可以从插件市场中选择需要的插件安装即可使用。

    那对于高度扩展性的设计理念Dubbo是怎么实现的呢?官网中Dubbo的扩展点高达几十个!!!

    5c60085970a4c3872730d5688e58f885.png

    图1:SPI扩展实现

    Java SPI使用以及不足之处

    再说Dubbo SPI前,我们还是有必要先说一下Java的SPI机制(做一下预热,因为Dubbo的SPI机制功能更加强大也更加复杂);

    对于Java SPI的使用是比较简单的(Java SPI实现原理以后有时间的话可以给大家再说一下);

    1.首先我们肯定是要先定义扩展接口;

    public interface Computer {  // 打开电脑    void start();}

    2.我们再需要定义一些实现类,我这里实现两个意思一下;

    public class Mac implements Computer {    @Override    public void start() {        System.out.println("你的mac电脑正在打开......");    }}public class Thinkpad implements Computer {    @Override    public void start() {        System.out.println("你的Thinkpad电脑正在打开......");    }}

    3.然后再在项目reources目录下新建一个META-INF/services文件夹,然后再新建一个以Computer接口的全限定名命名的文件,文件内容如下所示;

    com.demo.spi.Maccom.demo.spi.Thinkpad

    4.上面的步骤就类似于烧饭时我们的原材料已经准备完毕,下面我们需要再使用锅进行炒菜;这边的一个关键就是使用ServiceLoader的load方法去创建对应的服务加载器,然后通过服务加载器去加载实例;

    ServiceLoader serviceLoader = ServiceLoader.load(Computer.class);Iterator iterator = loadedParsers.iterator();while (iterator.hasNext()){  Computer computer = iterator.next();  Computer.start();}

    从上面的形式可以看出来原生的Java SPI机制缺点就是会一次性加载所有的扩展实现,如果有的扩展吃实话很耗时,但也没用上很浪费资源。

    Dubbo SPI实现逻辑

    现在回到正题就是Dubbo是如何对Java的SPI机制进行改进的?我这里总结以下几点:

    1.Java SPI 会一次性实例化扩展点所有实现,但是Dubbo可以实现按需加载实现类;

    2.如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。

    3.增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter 注入其它扩展点。

    4.Dubbo的扩展机制能很好的支持第三方IoC容器,默认支持Spring Bean。

    在以上改进项中,第一个改进项比较好理解。第二个改进项没有进行验证,就不多说了。第三、四个改进项是增加了对 IOC 和 AOP 的支持。

    下面就说一下Dubbo的SPI实现原理(Dubbo SPI使用我这边就不仔细说了,之前Dubbo负载负载均衡和容错机制文章中都有提到):

    1.我们首先通过ExtensionLoader(我们叫ExtensionLoader为扩展点加载器)的getExtensionLoader方法获取一个ExtensionLoader实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。

    T t = ExtensionLoader.getExtensionLoader(T.class).getExtendsion();

    getExtensionLoader(...)用于判断接口上是否有@SPI注解(扩展点)和类型必须是接口。

    public static  ExtensionLoader getExtensionLoader(Class type) {  if (type == null) {    throw new IllegalArgumentException("Extension type == null");  } else if (!type.isInterface()) { // 是否是接口    throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");  } else if (!withExtensionAnnotation(type)) { // 是否标记有SPI注解    throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");  } else {    // 这里加了缓存机制    ExtensionLoader loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);    if (loader == null) {      EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));      loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);    }    return loader;  }}

    2. 根据扩展实现类的别名name调用getExtension(String name)方法获取扩展对象(如果传入的name为"true",则获取默认的扩展实现类实例,即通过@SPI注解的value属性指定的默认扩展实现类别名,此时如果未设置value值则返回 null)。

    public T getExtension(String name) {  if (StringUtils.isEmpty(name)) {    throw new IllegalArgumentException("Extension name == null");  } else if ("true".equals(name)) { // 默认扩展实现对象    return this.getDefaultExtension();  } else {    Holder holder = this.getOrCreateHolder(name);    Object instance = holder.get();    if (instance == null) {      synchronized(holder) {        instance = holder.get();        // 创建扩展实现类        if (instance == null) {          instance = this.createExtension(name);          holder.set(instance);        }      }    }    return instance;  }}

    3.创建扩展实现类主要分为以下几个步骤:

    3.1.加载扩展实现类;

    3.2.反射创建扩展实现类的实例对象;

    3.3.实例对象属性注入;

    3.4.遍历包装类列表 cachedWrapperClasses,创建包装类实例,并注入依赖。

    private T createExtension(String name) {  // 加载扩展实现类clazz(这里也是有Map缓存的)  Class> clazz = (Class)this.getExtensionClasses().get(name);  if (clazz == null) {    throw this.findException(name);  } else {    try {      // 反射创建扩展实现类的实例对象(这里也是有Map缓存)      T instance = EXTENSION_INSTANCES.get(clazz);      if (instance == null) {        EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());        instance = EXTENSION_INSTANCES.get(clazz);      }      // 注入实例对象属性值      this.injectExtension(instance);      // 遍历包装类列表 cachedWrapperClasses,创建包装类实例,并注入依赖      Set> wrapperClasses = this.cachedWrapperClasses;      Class wrapperClass;      if (CollectionUtils.isNotEmpty(wrapperClasses)) {        for(Iterator var5 = wrapperClasses.iterator(); var5.hasNext(); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance))) {          wrapperClass = (Class)var5.next();        }      }      this.initExtension(instance);      return instance;    } catch (Throwable var7) {      throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var7.getMessage(), var7);    }  }}

    Dubbo中SPI加载路径(ExtensionLoader中直接可以看到):

    META-INF/dubbo/internal/META-INF/dubbo/META-INF/services/

    其实到这里Dubbo的SPI实现逻辑基本就已经结束了,但是Dubbo为了动态化、可以实时选择不同的扩展类又引入了一套自适应扩展机制。

    Dubbo自适应扩展机制

    Dubbo的自适应扩展机制从本质上的实现原理还是代理模式。

    首先 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类,在代理类中,就可以通过URL对象的参数来确定到底调用哪个实现类。

    自适应扩展使用(以负载均衡为例):

    // 先在SPI基础上,在需要的方法或者类加上@Adaptive注解@SPI("dubbo")public interface Protocol {    int getDefaultPort();    @Adaptive     Exporter export(Invoker invoker) throws RpcException;    @Adaptive     Invoker refer(Class type, URL url) throws RpcException;// 获取动态拓展对象ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

    在getAdaptiveExtension中会进行javassist动态编译,编译完之后就可以根据入参的URL进行判断选择哪个Name,再进行ExtensionLoader.getExtensionLoader(Class).getExtension(name),正常调用;

    // 进行动态编译private Class> createAdaptiveExtensionClass() {  String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();  ClassLoader classLoader = findClassLoader();  Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();  return compiler.compile(code, classLoader);}

    我们直接看一下编译后的代码大致的样子:

    public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {      // ......      // 典型的代理模式    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");        if (arg0.getUrl() == null)            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");        com.alibaba.dubbo.common.URL url = arg0.getUrl();        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());        if (extName == null)            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);        return extension.export(arg0);    }    // ......}

    到这里Dubbo的整套SPI机制已经将完,大家可以试着自己基于Spring做一套Spring SPI机制,友情提示一下可以基于FactoryBean、代理模式和Map做缓存。

    展开全文
  • Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你...

    Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你工作原理分层都搞明白了这个问题其实也就相当于回答了不是吗。

    说说Dubbo的分层?

    从大的范围来说,dubbo分为三层,business业务逻辑层由我们自己来提供接口和实现还有一些配置信息,RPC层就是真正的RPC调用的核心层,封装整个RPC的调用过程、负载均衡、集群容错、代理,remoting则是对网络传输协议和数据转换的封装。

    划分到更细的层面,就是图中的10层模式,整个分层依赖由上至下,除开business业务逻辑之外,其他的几层都是SPI机制。

    69a68bf91c6b4e0434ac107e5d419f92.png

     

     

    能说下Dubbo的工作原理吗?

    1. 服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务
    2. register根据服务订阅关系,返回provider信息到consumer,同时consumer会把provider信息缓存到本地。如果信息有变更,consumer会收到来自register的推送
    3. consumer生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向monitor记录接口的调用次数和时间信息
    4. 拿到代理对象之后,consumer通过代理对象发起接口调用
    5. provider收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现
    be902ca91b3ca0c72499bc5b02838251.png

     

    为什么要通过代理对象通信?

    主要是为了实现接口的透明代理,封装调用细节,让用户可以像调用本地方法一样调用远程方法,同时还可以通过代理实现一些其他的策略,比如:1、调用的负载均衡策略2、调用失败、超时、降级和容错机制3、做一些过滤操作,比如加入缓存、mock数据4、接口调用数据统计

     

     

    说说服务暴露的流程?

    1. 在容器启动的时候,通过ServiceConfig解析标签,创建dubbo标签解析器来解析dubbo的标签,容器创建完成之后,触发ContextRefreshEvent事件回调开始暴露服务
    2. 通过ProxyFactory获取到invoker,invoker包含了需要执行的方法的对象信息和具体的URL地址
    3. 再通过DubboProtocol的实现把包装后的invoker转换成exporter,然后启动服务器server,监听端口
    4. 最后RegistryProtocol保存URL地址和invoker的映射关系,同时注册到服务中心
    cacf7fa32b93b2e6fb1a4c14db9740c9.png

     

     

    说说服务引用的流程?

    服务暴露之后,客户端就要引用服务,然后才是调用的过程。
    1. 首先客户端根据配置文件信息从注册中心订阅服务
    2. 之后DubboProtocol根据订阅的得到provider地址和接口信息连接到服务端server,开启客户端client,然后创建invoker
    3. invoker创建完成之后,通过invoker为服务接口生成代理对象,这个代理对象用于远程调用provider,服务的引用就完成了
      7a3b0c3e308ba83b24e5b8b69233c394.png

     

     

    有哪些负载均衡策略?

    1. 加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了。
    2. 最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求。
    3. 一致性hash:通过hash算法,把provider的invoke和随机节点生成hash,并将这个 hash 投射到 [0, 2^32 - 1] 的圆环上,查询的时候根据key进行md5然后进行hash,得到第一个节点的值大于等于当前hash的invoker。
    a33c26d231fd8da39dffc211fbfca019.png
    图片来自dubbo官方
    1. 加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求。

     

     

    集群容错方式有哪些?

    1. Failover Cluster失败自动切换:dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为1也就是只调用一次。
    2. Failback Cluster快速失败:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试
    3. Failfast Cluster失败自动恢复:只会调用一次,失败后立刻抛出异常
    4. Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果
    5. Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返回了结果,就会立刻返回结果
    6. Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常。

     

     

    了解Dubbo SPI机制吗?

    SPI 全称为 Service Provider Interface,是一种服务发现机制,本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类,这样可以在运行时,动态为接口替换实现类。Dubbo也正是通过SPI机制实现了众多的扩展功能,而且dubbo没有使用java原生的SPI机制,而是对齐进行了增强和改进。SPI在dubbo应用很多,包括协议扩展、集群扩展、路由扩展、序列化扩展等等。使用方式可以在META-INF/dubbo目录下配置:
    key=com.xxx.value
    然后通过dubbo的ExtensionLoader按照指定的key加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。

     

     

    如果让你实现一个RPC框架怎么设计?

    1. 首先需要一个服务注册中心,这样consumer和provider才能去注册和订阅服务
    2. 需要负载均衡的机制来决定consumer如何调用客户端,这其中还当然要包含容错和重试的机制
    3. 需要通信协议和工具框架,比如通过http或者rmi的协议通信,然后再根据协议选择使用什么框架和工具来进行通信,当然,数据的传输序列化要考虑
    4. 除了基本的要素之外,像一些监控、配置管理页面、日志是额外的优化考虑因素。
    那么,本质上,只要熟悉一两个RPC框架,就很容易想明白我们自己要怎么实现一个RPC框架。有道无术,术可成;有术无道,止于术欢迎大家关注Java之道公众号f828f662976e84b464b9fbcb049433e5.png好文章,我在看❤️
    展开全文
  • 来点Dubbo相关的面试题1,问:当zookeeper挂了之后,生产者消费者之间还能通信吗?答:可以。因为当启动dubbo容器时,消费者会去zookeeper拉取注册的生产者地址列表,并将其缓存在本地。每次发起调用时,都会按照...
  • Spring Cloudspring cloud基本概念SpringCloudy 容器化讲讲springcloud个组件原理,zuul、Hystrix讲一讲springcloud的eureka组件?gatewayzuul做网关的区别?Spring cloud相关: (1)Eureka服务注册发现,对比...
  • Apache Dubbo Project Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the official site for the quick start guide and documentation, as well as the wiki ...
  • 我们角度仅仅不能满足使用,深层的意义就是满足底层远离实现机制。(一)RPC协议与使用场景在一个典型RPC的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中RPC协议就指明...
  • Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你...
  • 本章首先介绍现有Dubbo加载机制的概况,包括Dubbo所做的改进及部分特性。其次介绍加载机制中已经存在的一些关键注解,如@SPI、©Adaptive> ©Activateo然后介绍整个加载机制中最核心的ExtensionLoader的工作流程...
  • Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你...
  • 作者 | 刘军(陆龟) Apache Dubbo PMC概述社区版本 Dubbo 从 2.7.5 版本开始,新引入了一种基于实例(应用)粒度的服务发现机制,这是我们为 Dubbo 适配云原生基础设施的一步重要探索。版本发布到现在已有近半年...
  • 专注于Java领域优质技术,欢迎关注作者:Dean Wangdubbo是什么dubbo是一个分布式框架,远程服务调用的分布式框架,其核心部分包含: 集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡...
  • 面试题dubbo 负载均衡策略集群容错策略都有哪些?动态代理策略呢?面试官心理分析继续深问吧,这些都是用 dubbo 必须知道的一些东西,你得知道基本原理,知道序列化是什么协议,还得知道具体用 dubbo 的时候,如何...
  • Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你...
  • 1 面试题Dubbo负载均衡策略集群容错策略都有哪些?动态代理策略呢?2 考点分析这些都是关于Dubbo必须知道,基本原理,序列化是什么协议,具体用dubbo的时候,如何负载均衡,如何高可用,如何动态代理等.就是看你对...
  • Dubbo本身并不复杂,而且官方文档写的非常清楚详细,面试中dubbo的问题一般不会很多,从分层到工作原理、负载均衡策略、容错机制、SPI机制基本就差不多了,最大的一道大题一般就是怎么设计一个RPC框架了,但是如果你...
  • 单一应用架构当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。垂直应用架构当访问量逐渐增大,单一应用增加机器带来的加...
  • Dubbo基本原理机制

    2019-09-24 07:29:15
    Dubbo基本原理机制 分布式服务框架: –高性能透明化的RPC远程服务调用方案 –SOA服务治理方案 -Apache MINA框架基于Reactor模型通信框架,基于tcp长连接 Dubb...
  • dubbo启动时默认有重试机制和超时机制。超时机制的规则是如果在一定的时间内,provider没有返回,则认为本次调用失败,重试机制在出现调用失败时,会再次调用。如果在配置的调用次数内都失败,则认为此次请求异常,...
  • dubbo启动时默认有重试机制和超时机制。超时机制的规则是如果在一定的时间内,provider没有返回,则认为本次调用失败,重试机制在出现调用失败时,会再次调用。如果在配置的调用次数内都失败,则认为此次请求异常,...
  • dubbo实现原理机制

    千次阅读 2019-05-26 18:12:22
    Dubbo的总体架构如图所示: 框架分层架构中,各个层次的设计要点: 服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方服务消费方的业务设计对应的接口实现。 配置层(Config):对外配置...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 363
精华内容 145
关键字:

dubbo原理和机制