温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

dubbo的重要知识点总结

发布时间:2021-09-09 11:54:50 来源:亿速云 阅读:164 作者:chen 栏目:大数据

本篇内容主要讲解“dubbo的重要知识点总结”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“dubbo的重要知识点总结”吧!

dubbo架构

Provider: 暴露服务的提供方,可以通过jar或者容器的方式启动服务
Consumer:调用远程服务的服务消费方。
Registry: 服务注册中心和发现中心。
Monitor: 统计服务的调用次数、调用时间
Container:服务运行的容器。

Dubbo的网络传输协议

RPC通讯协议

Dubbo提供的序列化方式

  • dubbo:Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况

  • rmi:RMI协议采用JDK标准的java.rmi.*实现,采用阻塞式短连接和JDK标准序列化方式

  • Hessian:Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现

  • http:采用Spring的HttpInvoker实现

  • Webservice:基于CXF的frontend-simple和transports-http实现

Dubbo的注册中心

默认是zk,其他还有Redis、Multicast、Simple 注册中心,但不推荐。

Dubbo有哪几种配置方式?

Spring 配置方式(XML文件)
Java API 配置方式(注解方式)

Dubbo的核心配置

  • dubbo:service       服务配置(作为服务的提供者,暴露服务的配置)

  • dubbo:reference     引用配置(需要调用外部服务)

  • dubbo:protocol      协议配置(服务支持的协议配置,若需要支持多个协议,可以声明多个<dubbo:protocol>标签)

  • dubbo:application   应用配置(应用信息配置,包括当前应用名、应用负责人、应用版本、应用环境等)

  • dubbo:module        模块配置(模块信息配置,包括当前模块名、模块负责人、模块版本等)

  • dubbo:registry      注册中心配置(同时如果有多个不同的注册中心,可以声明多个 <dubbo:registry> 标签,并在 <dubbo:service> 或 <dubbo:reference> 的 registry 属性指定使用的注册中心。)

  • dubbo:monitor       监控中心配置(有protocol、address两个属性,当protocol="registry",表示从注册中心发现监控中心地址,当address="10.20.130.230:12080"表示直连监控中心地址)

  • dubbo:provider      提供方配置(服务提供者缺省值配置,该标签为 <dubbo:service> 和 <dubbo:protocol> 标签的缺省值设置。)

  • dubbo:consumer      消费方配置(服务消费者缺省值配置,该标签为 <dubbo:reference> 标签的缺省值设置。)

  • dubbo:method        方法配置(该标签为 <dubbo:service> 或 <dubbo:reference> 的子标签,用于控制到方法级。)

  • dubbo:argument      参数配置(该标签为 <dubbo:method> 的子标签,用于方法参数的特征描述)

Timeout的超时时间

在dubbo的provider和consumer的配置文件中,如果都配置了timeout的超时时间,dubbo默认以consumer中配置的时间为准。
如下例子:
在provider.xml的配置:

<dubbo:service timeout="4000" retries="0" interface="com.dingding.tms.bms.service.BillingZfbCodOrderService" ref="billingZfbCodOrderService" registry="globalRegistry"/>

conusmer中的配置:

<dubbo:reference id="billingInterService" interface="com.dingding.tms.bms.service.BillingInterService" protocol="dubbo" check="false" registry="globalRegistry" timeout="3000"/>

最后这个service在调用时的超时时间就是3秒。
另外:
1.consumer会在超过3秒时得到一个调用超时的异常。
2.provider中代码的执行不会因为超时而中断,在执行完毕后,会得到一个dubbo的警告。

在Provider上尽量多配置Consumer端属性

在dubbo的用户手册中,对配置有这样的推荐用法:在Provider上尽量多配置Consumer端属性
原因如下:
作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
PS: 配置的覆盖规则:

  • 方法级配置级别优于接口级别,即小Scope优先 

  • Consumer端配置 优于 Provider配置 优于 全局配置,最后是Dubbo Hard Code的配置值(见配置文档)

在 Provider 可以配置的 Consumer 端属性有:

  • timeout:方法调用超时

  • retries:失败重试次数,缺省是2(表示加上第一次调用,会调用3次)

  • loadbalance:负载均衡算法(有多个Provider时,如何挑选Provider调用),缺省是随机(random)。还可以有轮训(roundrobin)、最不活跃优先(leastactive,指从Consumer端并发调用最好的Provider,可以减少的反应慢的Provider的调用,因为反应更容易累积并发的调用)

  • actives:消费者端,最大并发调用限制,即当Consumer对一个服务的并发调用到上限后,新调用会Wait直到超时。在方法上配置(dubbo:method )则并发限制针对方法,在接口上配置(dubbo:service),则并发限制针对服务。

Dubbo 启动时如果依赖的服务不可用会怎样?

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。

Dubbo支持的序列化框架

推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。

Dubbo使用的通信框架

Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly

Dubbo的集群容错方案

  • Failover Cluster    失败自动切换,自动重试其它服务器(默认) 

  • Failfast Cluster    快速失败,立即报错,只发起一次调用 

  • Failsafe Cluster    失败安全,出现异常时,直接忽略 

  • Failback Cluster    失败自动恢复,记录失败请求,定时重发 

  • Forking Cluster     并行调用多个服务器,只要一个成功即返回 

  • Broadcast Cluster   广播逐个调用所有提供者,任意一个报错则报错

Dubbo的负载均衡策略

  • Random LoadBalance          随机,按权重设置随机概率(默认) 

  • RoundRobin LoadBalance      轮询,按公约后的权重设置轮询比率

  • LeastActive LoadBalance     最少活跃调用数,相同活跃数的随机 

  • ConsistentHash LoadBalance  一致性 Hash,相同参数的请求总是发到同一提供者

注册了多个同一样的服务,如果需要测试指定的某一个服务该怎么做

可以配置环境点对点直连,绕过注册中心,将以服务接口为单位,忽略注册中心的提供者列表。

Dubbo支持服务多协议

Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。
不同服务不同协议:

    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="20980" />

    <!-- 使用dubbo协议暴露服务 -->
    <dubbo:service interface="com.ricky.dubbo.api.DemoService" ref="demoService" protocol="dubbo"/>
    <!-- 使用rmi协议暴露服务 -->
    <dubbo:service interface="com.ricky.dubbo.api.HelloService" ref="helloService" protocol="rmi"/>

同一服务多种协议

    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="20980" />

    <!-- 使用rmi协议暴露服务 -->
    <dubbo:service interface="com.ricky.dubbo.api.HelloService" ref="helloService" protocol="dubbo,rmi"/>

当一个服务接口有多种实现时怎么做

当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可。
提供端:

<dubbo:service interface="…" ref="…" group="实现1" />
<dubbo:service interface="…" ref="…" group="实现2" />

消费端:

<dubbo:reference id="…" interface="…" group="实现1" />
<dubbo:reference id="…" interface="…" group="实现2" />

服务上线怎么兼容旧版本?

可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。例如:
服务提供方:

<dubbo:service interface="com.foo.BarService" version="1.0.0" />
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

服务消费方:

<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

此外,消费者消费服任意版本的服务时:

<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

Dubbo的结果缓存机制

Dubbo 提供了声明式缓存,用于加速热门数据的访问速度,以减少用户加缓存的工作量,使用方式:

<dubbo:reference interface="com.foo.BarService" cache="threadlocal" />

Dubbo提供的三种缓存接口的入口,三种方式均继承了 AbstractCacheFactory 接口,分别是:

  • 1.threadlocal=com.alibaba.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory

  • 2.lru=com.alibaba.dubbo.cache.support.lru.LruCacheFactory(LRU基于最近最少使用原则删除多余缓存,保持最热的数据被缓存;该类型的缓存是跨线程的;利用链表实现,新数据插入表头、缓存命中数据移到表头、链表满时删除表尾数据)

  • 3.jcache=com.alibaba.dubbo.cache.support.jcache.JCacheFactory

Dubbo 同步/异步调用

Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制;基于这种机制,Dubbo 实现了以下几种调用方式:

  • 同步调用

  • 异步调用

  • 参数回调

  • 事件通知

Dubbo 同步调用

同步调用是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止;
通常,一个典型的同步调用过程如下:

  1. Consumer 业务线程调用远程接口,向 Provider 发送请求,同时当前线程处于阻塞状态;

  2. Provider 接到 Consumer 的请求后,开始处理请求,将结果返回给 Consumer;

  3. Consumer 收到结果后,当前线程继续往后执行。

这里有 2 个问题:

  • Consumer 业务线程是怎么进入阻塞状态的?

  • Consumer 收到结果后,如何唤醒业务线程往后执行的?

其实,Dubbo 的底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过Future#get(timeout),阻塞等待 Provider 端将结果返回;timeout则是 Consumer 端定义的超时时间。当结果返回后,会设置到此 Future,并唤醒阻塞的业务线程;当超时时间到结果还未返回时,业务线程将会异常返回。

Dubbo 异步调用

dubbo的重要知识点总结

dubbo的重要知识点总结

基于 Dubbo 底层的异步 NIO 实现异步调用,对于 Provider 响应时间较长的场景是必须的,它能有效利用 Consumer 端的资源,相对于 Consumer 端使用多线程来说开销较小。异步调用,对于 Provider 端不需要做特别的配置。
在 Consumer 端配置需要异步调用的方法,均需要使用 <dubbo:method/>标签进行描述:

<dubbo:reference id="asyncService" interface="com.alibaba.dubbo.samples.async.api.AsyncService">
    <dubbo:method name="goodbye" async="true"/>
</dubbo:reference>

Dubbo Consumer 端发起调用后,同时通过RpcContext.getContext().getFuture()获取跟返回结果关联的Future对象,然后就可以开始处理其他任务;当需要这次异步调用的结果时,可以在任意时刻通过future.get(timeout)来获取。
一些特殊场景下,为了尽快调用返回,可以设置是否等待消息发出:

  • sent="true" 等待消息发出,消息发送失败将抛出异常;

  • sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。

默认为false。配置方式如下:

<dubbo:method name="goodbye" async="true" sent="true" />

如果你只是想异步,完全忽略返回值,可以配置 return="false",以减少 Future 对象的创建和管理成本:

<dubbo:method name="goodbye" async="true" return="false" />

此时,RpcContext.getContext().getFuture()将返回null。

Dubbo 参数回调

参数回调有点类似于本地 Callback 机制,但 Callback 并不是 Dubbo 内部的类或接口,而是由 Provider 端自定义的;Dubbo 将基于长连接生成反向代理,从而实现从 Provider 端调用 Consumer 端的逻辑。

Provider 端定义 Service 和 Callback:

public interface CallbackService {
    void addListener(String key, CallbackListener listener);
}

public interface CallbackListener {
    void changed(String msg);
}

Provider 端实现 service :

public class CallbackServiceImpl implements CallbackService {

    private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();

    public CallbackServiceImpl() {
        Thread t = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        for (Map.Entry<String, CallbackListener> entry : listeners.entrySet()) {
                            try {
                                entry.getValue().changed(getChanged(entry.getKey()));
                            } catch (Throwable t) {
                                listeners.remove(entry.getKey());
                            }
                        }
                        Thread.sleep(5000); // timely trigger change event
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            }
        });
        t.setDaemon(true);
        t.start();
    }

    public void addListener(String key, CallbackListener listener) {
        listeners.put(key, listener);
        listener.changed(getChanged(key)); // send notification for change
    }

    private String getChanged(String key) {
        return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
}

在 Provider 端暴露服务:

<bean id="callbackService" class="com.alibaba.dubbo.samples.callback.impl.CallbackServiceImpl"/>

<dubbo:service interface="com.alibaba.dubbo.samples.callback.api.CallbackService" ref="callbackService" connections="1" callbacks="1000">
    <dubbo:method name="addListener">
        <!-- index 表示参数索引,如下 index=1 ,表示第一个参数是 callback 回调参数 -->
        <dubbo:argument index="1" callback="true"/>
        <!--<dubbo:argument type="com.demo.CallbackListener" callback="true" />-->
    </dubbo:method>
</dubbo:service>

Consumer 端实现 Callback 接口

CallbackService callbackService = ...;
callbackService.addListener("foo.bar", new CallbackListener() {
        public void changed(String msg) {
            System.out.println("callback1:" + msg);
        }
});

Callback 接口的实现类在 Consumer 端,当方法发生调用时,Consumer 端会自动 export 一个 Callback 服务。而 Provider 端在处理调用时,判断如果参数是 Callback,则生成了一个 proxy,因此服务实现类里在调用 Callback 方法的时候,会被传递到 Consumer 端执行 Callback 实现类的代码。

Dubbo 事件通知

事件通知允许 Consumer 端在调用之前、调用之后或出现异常时,触发 oninvoke、onreturn、onthrow 三个事件。
可以通过在配置 Consumer 时,指定事件需要通知的方法,如:

<bean id="demoCallback" class="com.alibaba.dubbo.samples.notify.impl.NotifyImpl" />

<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.samples.notify.api.DemoService" version="1.0.0" group="cn">
    <dubbo:method name="sayHello" onreturn="demoCallback.onreturn" onthrow="demoCallback.onthrow"/>
</dubbo:reference>

其中,NotifyImpl 的代码如下:

public class NotifyImpl implements Notify {

    public Map<Integer, String> ret = new HashMap<Integer, String>();
    
    public void onreturn(String name, int id) {
        ret.put(id, name);
        System.out.println("onreturn: " + name);
    }

    public void onthrow(Throwable ex, String name, int id) {
        System.out.println("onthrow: " + name);
    }
}

这里要强调一点,自定义 Notify 接口中的三个方法的参数规则如下:

  • oninvoke 方法参数与调用方法的参数相同;

  • onreturn方法第一个参数为调用方法的返回值,其余为调用方法的参数;

  • onthrow方法第一个参数为调用异常,其余为调用方法的参数。

上述配置中,sayHello方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 async=true 让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下, oninvoke 方法不管是否异步调用,都是同步执行的。

Dubbo 支持分布式事务吗?

目前暂时不支持,后续可能采用基于 JTA/XA 规范实现

Dubbo 服务降级(2.2.0以上的版本支持)

可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
向注册中心写入动态配置覆盖规则:

  • RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();

  • Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));

  • registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));

其中:
mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要的服务不可用时,对调用方的影响。
还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

Dubbo 如何优雅停机?

Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。

  • 服务提供方:停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。

  • 服务消费方:停止时,不再发起新的调用请求,所有新的调用在客户端即报错。然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。

Dubbo 的服务提供者能实现失效踢出是什么原理?

服务失效踢出是基于 Zookeeper 的临时节点原理。
zk 中的节点分为临时节点和永久节点,节点的类型在创建时即被确定,并且不能改变。

  • ZooKeeper的临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当然可以也可以手动删除。另外,需要注意是,ZooKeeper的临时节点不允许拥有子节点。

  • ZooKeeper的永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

在分布式系统中,我们常常需要知道某个机器是否可用,传统的开发中,可以通过Ping某个主机来实现,Ping得通说明对方是可用的,相反是不可用的。
在 ZK 中我们让所有的机器都注册一个临时节点,要判断一个节点是否可用,我们只需要判断这个临时节点在 ZK 中是否存在就可以了,不需要直接去连接需要检查的机器,降低系统的复杂度。

Dubbo 服务读写推荐的容错策略是怎样的?

读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器。
写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错。

如何解决服务调用链过长的问题?

Dubbo 可以使用 Pinpoint 和 Apache Skywalking(Incubator) 实现分布式服务追踪,当然还有其他很多方案。

Dubbo 的管理控制台能做什么?

管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。

到此,相信大家对“dubbo的重要知识点总结”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI