本篇内容主要讲解“dubbo的重要知识点总结”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“dubbo的重要知识点总结”吧!
Provider: 暴露服务的提供方,可以通过jar或者容器的方式启动服务
Consumer:调用远程服务的服务消费方。
Registry: 服务注册中心和发现中心。
Monitor: 统计服务的调用次数、调用时间
Container:服务运行的容器。
RPC通讯协议
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实现
默认是zk,其他还有Redis、Multicast、Simple 注册中心,但不推荐。
Spring 配置方式(XML文件)
Java API 配置方式(注解方式)
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> 的子标签,用于方法参数的特征描述)
在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的警告。
在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 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。
推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。
Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly
Failover Cluster 失败自动切换,自动重试其它服务器(默认)
Failfast Cluster 快速失败,立即报错,只发起一次调用
Failsafe Cluster 失败安全,出现异常时,直接忽略
Failback Cluster 失败自动恢复,记录失败请求,定时重发
Forking Cluster 并行调用多个服务器,只要一个成功即返回
Broadcast Cluster 广播逐个调用所有提供者,任意一个报错则报错
Random LoadBalance 随机,按权重设置随机概率(默认)
RoundRobin LoadBalance 轮询,按公约后的权重设置轮询比率
LeastActive LoadBalance 最少活跃调用数,相同活跃数的随机
ConsistentHash LoadBalance 一致性 Hash,相同参数的请求总是发到同一提供者
可以配置环境点对点直连,绕过注册中心,将以服务接口为单位,忽略注册中心的提供者列表。
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: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 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制;基于这种机制,Dubbo 实现了以下几种调用方式:
同步调用
异步调用
参数回调
事件通知
同步调用是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止;
通常,一个典型的同步调用过程如下:
Consumer 业务线程调用远程接口,向 Provider 发送请求,同时当前线程处于阻塞状态;
Provider 接到 Consumer 的请求后,开始处理请求,将结果返回给 Consumer;
Consumer 收到结果后,当前线程继续往后执行。
这里有 2 个问题:
Consumer 业务线程是怎么进入阻塞状态的?
Consumer 收到结果后,如何唤醒业务线程往后执行的?
其实,Dubbo 的底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过Future#get(timeout),阻塞等待 Provider 端将结果返回;timeout则是 Consumer 端定义的超时时间。当结果返回后,会设置到此 Future,并唤醒阻塞的业务线程;当超时时间到结果还未返回时,业务线程将会异常返回。
基于 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。
参数回调有点类似于本地 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 实现类的代码。
事件通知允许 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 方法不管是否异步调用,都是同步执行的。
目前暂时不支持,后续可能采用基于 JTA/XA 规范实现
可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
向注册中心写入动态配置覆盖规则:
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 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。
服务提供方:停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
服务消费方:停止时,不再发起新的调用请求,所有新的调用在客户端即报错。然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
服务失效踢出是基于 Zookeeper 的临时节点原理。
zk 中的节点分为临时节点和永久节点,节点的类型在创建时即被确定,并且不能改变。
ZooKeeper的临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当然可以也可以手动删除。另外,需要注意是,ZooKeeper的临时节点不允许拥有子节点。
ZooKeeper的永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
在分布式系统中,我们常常需要知道某个机器是否可用,传统的开发中,可以通过Ping某个主机来实现,Ping得通说明对方是可用的,相反是不可用的。
在 ZK 中我们让所有的机器都注册一个临时节点,要判断一个节点是否可用,我们只需要判断这个临时节点在 ZK 中是否存在就可以了,不需要直接去连接需要检查的机器,降低系统的复杂度。
读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器。
写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错。
Dubbo 可以使用 Pinpoint 和 Apache Skywalking(Incubator) 实现分布式服务追踪,当然还有其他很多方案。
管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。
到此,相信大家对“dubbo的重要知识点总结”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。