Dubbo基本概念

文章目录

    • 一、初识Dubbo
      • 1.1 Dubbo解决的问题
      • 1.2 Dubbo与Spring Cloud的区别
      • 1.3 Dubbo特性
        • 1.3.1 连通性
        • 1.3.2 健状性
        • 1.3.3 伸缩性
    • 二、Dubbo架构设计
      • 2.1 从角色理解架构
        • 2.1.1 五个角色
        • 2.1.2 角色设计的好处
      • 2.2 从分层理解架构
      • 2.3 线程模型
      • 2.4 所用协议
        • 2.4.1 Dubbo所支持协议的应用场景及优缺点
        • 2.4.2 Dubbo协议特点
        • 2.4.3 Dubbo协议常见问题
      • 2.5 架构特性
        • 2.5.1 集群容错
        • 2.5.2 负载均衡
      • 2.6 Monitor实现原理
    • 三、Dubbo附加功能
      • 3.1 服务分组
      • 3.2 多版本
      • 3.3 异步调用
      • 3.4 事件通知
      • 3.5 本地伪装
      • 3.6 令牌验证
      • 3.7 写入路由规则
      • 3.8 优雅停机
      • 3.9 注册中心
        • 3.9.1 流程说明
        • 3.9.2 Dubbo注册中心分类
        • 3.9.3 Dubbo注册中心的相关问题
      • 3.10 Dubbo配置
        • 3.10.1 Dubbo的核心配置及作用
        • 3.10.2 Dubbo的配置优先级
        • 3.10.3 Dubbo的配置来源有几种,分别是什么
        • 3.10.4 开发测试环境,想绕过注册中心如何配置
        • 3.10.5 Dubbo配置文件是如何加载到Spring中的
    • 四、Dubbo使用注意事项
      • 4.1 最佳实践
      • 4.2 使用建议
    • 五、相关问题
      • 5.1 Dubbo支持哪些序列化方式?
      • 5.2 Dubbo超时时间怎样设置?
      • 5.3 服务调用超时问题怎么解决?
      • 5.4 Dubbo在安全机制方面的做法
      • 5.5 Dubbo支持服务降级吗?
      • 5.6 服务提供者能实现失效踢出是什么原理理?
      • 5.7 如何解决服务调用链过长的问题?
      • 5.8 服务读写推荐的容错策略是怎样的?
      • 5.9 Dubbo的管理控制台能做什么?
      • 5.10 Dubbo服务暴露的过程
      • 5.11 当一个服务接口有多种实现时怎么做?
      • 5.12 服务上线怎么兼容旧版本?
      • 5.13 Dubbo可以对结果进行缓存吗?
      • 5.14 Dubbo服务之间的调用是阻塞的吗?
      • 5.15 注册了多个同一样的服务,如果测试指定的某一个服务呢?
      • 5.16 Dubbo和Dubbox之间的区别?
      • 5.17 Dubbo对JDK版本的最低要求
      • 5.18 Dubbo服务调用默认是阻塞的吗
      • 5.19 IO线程池默认大小
      • 5.20 Dubbo服务降级,失败重试怎么做?
      • 5.21 Dubbo用到了哪些设计模式?
      • 5.22 Dubbo可以对结果进行缓存吗?
      • 5.23 Dubbo有哪几种配置方式?
      • 5.24 Dubbo启动时如果依赖的服务不可用会怎样?
      • 5.25 在Provider上可以配置的Consumer端的属性有哪些?
      • 5.26 Dubbo用到了哪些设计模式?
      • 5.27 Dubbo中Zookeeper做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信吗?

一、初识Dubbo

  Dubbo是一个分布式服务框架,致力于提高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单来说,Dubbo就是个远程服务调用的分布式框架。
  Dubbo具备的功能有:服务提供、服务调用、连接处理、通信协议、序列化方式、服务发现、服务路由、日志输出。
  Dubbo核心部分包括:

  1. 远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型序列化,以及“请求-响应”模式的信息交换方式。
  2. 集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡、失败容错、地址路由、动态配置等集群支持。
  3. 自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务器提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

  Dubbo能做什么?

  1. 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API入侵。
  2. 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本。
  3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能平滑添加或删除服务提供者。
  4. Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo配置即可,Dubbo基于Spring的Schema扩展进行加载。

  Dubbo默认使用NIO Netty通信框架。因此Dubbo不需要Web容器,如果硬要用Web容器,只会增加复杂性,也浪费资源。

1.1 Dubbo解决的问题

Dubbo基本概念_第1张图片
  在大规模服务化之前,应用可能只是通过RMI等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。
  当服务越来越多时,服务URL配置管理变得非常困难, F5硬件负载均衡器的单点压力也越来越大。此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。
  当进一步发展,服务间依赖关系变得错综复杂,甚至分不清哪个应用要在哪个应用之前启动。这时,需要画出应用间的依赖关系图,以帮助理清应用之间的服务调用关系。
  接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要用多少机器支撑?什么时候该加机器?为了解决这些问题,首先要将服务现在每天的调用量、响应时间等信息都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间达到阈值,记录此时的访问量,再依次访问量乘以机器数反推总容量。
  这就是Dubbo最基本的几个需求。概括起来,需要服务治理的几个原因:

过多的服务URL配置困难;
负载均衡分配节点压力过大的情况下也需要部署集群;
服务依赖混乱,启动顺序不清晰;
过多服务导致性能指标分析难度较大,需要监控。

1.2 Dubbo与Spring Cloud的区别

  Dubbo是SOA时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断。而Spring Cloud诞生于微服务架构时代,考虑的是微服务治理的方方面面,另外由于依托了Spirng、Spirng Boot的优势之上,两个框架在开始目标就不一致,Dubbo定位服务治理、Spirng Cloud是一个生态。

  • Dubbo和Spring Cloud的区别
Dubbo Spring Cloud
服务注册中心 Zookeeper Spring Cloud Netflix Eureka
服务调用方式 RPC REST API
服务网关 Spring Cloud Netflix Zuul
断路器 不完善 Spring Cloud Netflix Hystrix
分布式配置 Spring CLoud Config
服务跟踪 Spring Cloud Sleuth
消息总线 Spring CLoud Bus
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task

  Dubbo底层是使用Netty这样的NIO框架,是基于TCP协议传输的,配合以Hession序列化完成RPC通信
  SpringCloud是基于Http协议+Rest接口调用远程过程的通信,相对来说,Http请求会有更大的报文,占的带宽也会更多。但是REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖。

1.3 Dubbo特性

1.3.1 连通性

  • 1、注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。
  • 2、监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示。
  • 3、服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销。
  • 4、服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销。
  • 5、注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外。
  • 6、注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者。
  • 7、注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表。
  • 8、注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。

1.3.2 健状性

  • 1、监控中心宕掉不影响使用,只是丢失部分采样数据。
  • 2、数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务。
  • 3、注册中心对等集群,任意一台宕掉后,将自动切换到另一台。
  • 4、注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯。
  • 5、服务提供者无状态,任意一台宕掉后,不影响使用。
  • 6、服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复。

1.3.3 伸缩性

  • 1、注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心。
  • 2、服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者。

二、Dubbo架构设计

2.1 从角色理解架构

2.1.1 五个角色

Dubbo基本概念_第2张图片

  节点角色:

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次调和调用时间的监控中心
Container 服务运行容器

  Dubbo服务器注册与发现的流程:

  • 1、服务容器负责启动,加载,运行服务提供者。
  • 2、服务提供者在启动时,向注册中心注册自己提供的服务(发送本机 IP、端口、应用信息和提供服务信息发送至注册中心存储)。
  • 3、服务消费者在启动时,向注册中心订阅自己所需的服务(并发送应用信息、所求服务信息至注册中心)。
  • 4、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 5、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。服务提供者状态变更会实时通知注册中心、在由注册中心实时推送至服务消费者。
  • 6、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2.1.2 角色设计的好处

  Consumer与Provider解偶,双方都可以横向增减节点数。
  注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台。
  去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用。
  服务提供者无状态,任意一台宕掉后,不影响使用。
Dubbo基本概念_第3张图片

2.2 从分层理解架构

Dubbo基本概念_第4张图片
  Dubbo框架设计一共划分了10个层:

  • 1、服务接口层(Service)
      该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
  • 2、配置层(Config)
      对外配置接口,以ServiceConfig和ReferenceConfig为中心。
  • 3、服务代理层(Proxy)
      服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton。以ServiceProxy为中心,扩展接口为ProxyFactory。
  • 4、服务注册层(Registry)
      封装服务地址的注册与发现,以服务URL为中心。 扩展接口为RegistryFactory、Registry、RegistryService。
  • 5、集群层(Cluster)
      封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为 Cluster、Directory、Router和LoadBlance。
  • 6、监控层(Monitor)
      RPC调用次数和调用时间监控。以Statistics为中心, 扩展接口为MonitorFactory、Monitor和MonitorService。
  • 7、远程调用层(Protocol)
      封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。
  • 8、信息交换层(Exchange)
      封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、 ExchangeClient和ExchangeServer。
  • 9、网络传输层(Transport)
      抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
  • 10、数据序列化层(Serialize)
      数据传输的序列化和反序列化。扩展接口为Serialization、 ObjectInput、ObjectOutput和ThreadPool Dubbo。

2.3 线程模型

  如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识,则直接在IO线程上处理更快,因为减少了线程池调度。
  但如果事件处理逻辑较慢,或者需要发起新的IO请求,比如需要查询数据库,则必须派发到线程池,否则IO线程阻塞,将导致不能接收其它请求。
  如果用IO线程处理事件,又在事件处理过程中发起新的IO请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁。
Dubbo基本概念_第5张图片
  需要通过不同的派发策略和不同的线程池配置的组合来应对不同的场景:

	<dubbo:protocol name="dubbo" dispatcher="all" 
		threadpool="fixed" threads="100" />
  • Dispatcher
      all:所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
      direct:所有消息都不派发到线程池,全部在IO线程上直接执行。
      message:只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。
      execution:只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。
      connection:在IO线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
  • ThreadPool
      fixed:固定大小线程池,启动时建立线程,不关闭,一直持有(缺省)。
      cached:缓存线程池,空闲一分钟自动删除,需要时重建。
      limited:可伸缩线程池,但池中的线程数只会增长不会收缩。只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。

2.4 所用协议

  Dubbo默认使用dubbo协议。支持的协议有:dubbo://(推荐)、rmi://、hessian://、http://、webservice://、thrift://、memcached://、redis://、rest://。
  Dubbo的设计目的是为了满足高并发小数据量的rpc调用,在大数据量下的性能表现并不好,建议使用rmi或http 协议。
  这些协议对应的默认端口号:

dubbo:20880
http:80
hessian:80
rmi:80

2.4.1 Dubbo所支持协议的应用场景及优缺点

  • dubbo
      单一长连接和NIO异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。
      Dubbo协议适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用Dubbo协议传输大文件或超大字符串。
      Dubbo协议适用场景:常规远程服务方法调用。
      Dubbo协议实现:

连接个数:单连接;
连接方式:长连接;
传输协议:TCP;
传输方式:NIO异步传输;
序列化:Hessian二进制序列化。

  • rmi
      采用JDK标准的rmi协议实现,传输参数和返回参数对象需要实现Serializable接口,使用Java标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件。在依赖低版本的Common-Collections包,Java序列化存在安全漏洞。
      连接个数:多连接;
      连接方式:短连接;
      传输协议:TCP;
      传输方式:同步传输;
      序列化:Java 标准二进制序列化;
      适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件;
      适用场景:常规远程服务方法调用,与原生RMI服务互操作。
  • webservice
      基于CXF的frontend-simple和transports-http实现。
      基于WebService的远程调用协议。
      连接个数:多连接。
      连接方式:短连接。
      传输协议:HTTP。
      传输方式:同步传输。
      序列化:SOAP文本序列化。
      适用场景:系统集成,跨语言调用。
  • http
      采用Spring的HttpInvoker实现。
      基于http表单的远程调用协议。
      连接个数:多连接。
      连接方式:短连接。
      传输协议:HTTP。
      传输方式:同步传输。
      序列化:表单序列化(JSON)。
      适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
      适用场景:需同时给应用程序和浏览器JS使用的服务。
  • hessian
      Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现。
      基于 Hessian 的远程调用协议。
      连接个数:多连接。
      连接方式:短连接。
      传输协议:HTTP。
      传输方式:同步传输。
      序列化:Hessian二进制序列化。
      适用范围:传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。
      适用场景:页面传输,文件传输,或与原生hessian服务互操作。
  • memcache
      基于memcached实现的RPC协议。
  • redis
      基于redis实现的RPC协议。

2.4.2 Dubbo协议特点

  Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
  反之,Dubbo缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
Dubbo基本概念_第6张图片

  • 特性
      缺省协议,使用基于mina1.1.7和hessian3.2.1的tbremoting交互。
      连接个数:单连接。
      连接方式:长连接。
      传输协议:TCP。
      传输方式:NIO异步传输。
      序列化:Hessian二进制序列化。
      适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
      适用场景:常规远程服务方法调用。
  • 约束
      参数及返回值需实现Serializable接口。
      参数及返回值不能自定义实现List、Map、Number、Date、Calendar等接口,只能用JDK自带的实现,因为 hessian 会做特殊处理,自定义实现类中的属性值都会丢失。
      Hessian序列化,只传成员属性值和值的类型,不传方法或静态变量,兼容情况。
数据通讯 情况 结果
A -> B 类A多一种属性(或者说类B少一种属性) 不抛异常,A多的那个属性的值,B没有,其他正常
A -> B 枚举A多一种雷剧(或者说B少一种枚举),A使用多出来的枚举进行传输 抛异常
A -> B 枚举A多一种雷剧(或者说B少一种枚举),A不使用多出来的枚举进行传输 不抛异常,B正常接收数据
A -> B A和B的属性名相同,但类型不同 抛异常
A -> B 序列化ID不同 正常传输

  接口增加方法,对客户端无影响,如果该方法不是客户端需要的,客户端不需要重新部署。
  输入参数和结果集中增加属性,对客户端无影响,如果客户端并不需要新属性,不用重新部署。
  输入参数和结果集属性名变化,对客户端序列化无影响,但是如果客户端不重新部署,不管输入还是输出,属性名变化的属性值是获取不到的。
  总结:服务器端和客户端对领域对象并不需要完全一致,而是按照最大匹配原则。

2.4.3 Dubbo协议常见问题

  • 1、为什么要消费者比提供者个数多?
      因Dubbo协议采用单一长连接,假设网络为千兆网卡 ,根据测试经验数据每条连接最多只能压满7MByte(不同的环境可能不一样,供参考),理论上1个服务提供者需要20个服务消费者才能压满网卡。
  • 2、为什么不能传大包?
      因Dubbo协议采用单一长连接,如果每次请求的数据包大小为500KByte,假设网络为千兆网卡 ,每条连接最大7MByte(不同的环境可能不一样,供参考),单个服务提供者的TPS(每秒处理事务数)最大为:128MByte/500KByte=262。单个消费者调用单个服务提供者的 TPS(每秒处理事务数)最大为:7MByte/500KByte=14。如果能接受,可以考虑使用,否则网络将成为瓶颈。
  • 3、为什么采用异步单一长连接?
      因为服务的现状大都是服务提供者少,通常只有几台机器,而服务的消费者多,可能整个网站都在访问该服务,比如Morgan的提供者只有6台提供者,却有上百台消费者,每天有1.5亿次调用,如果采用常规的hessian服务,服务提供者很容易就被压跨,通过单一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步IO,复用线程池,防止C10K问题。
      网络服务在处理数以万计的客户端连接时,往往出现效率底下甚至完全瘫痪,这被成为C10K问题。(C10K = connection 10 kilo问题)。k表示kilo,即1000。比如:kilometer(千米),kilogram(千克)。
  • 4、Dubbo支持服务多协议吗?
      Dubbo允许配置多协议,在不同服务上支持不不同协议或者同一服务上同时支持多种协议。

2.5 架构特性

2.5.1 集群容错

Dubbo基本概念_第7张图片
  各节点的关系:

  1. 这里的Invoker是Provider的一个可调用Service的抽象, Invoker封装了Provider地址及Service接口信息。
  2. Directory代表多个Invoker,可以把它看成List,但与List不同的是,它的值可能是动态变化的,比如注册中心推送变更。
  3. Cluster将Directory中的多个Invoker伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个.
  4. Router负责从多个Invoker中按路由规则选出子集,比如读写分离,应用隔离等。
  5. LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。

  Dubbo的默认集群容错方案是Failover Cluster
  Dubbo的集群容错方案:

  • Failover Cluster
      失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2"来设置重试次数(不含第一次)。示例:
	<dubbo:service retries="2" cluster="failover"/>

  或者:

	<dubbo:reference retries="2" cluster="failover"/>

  cluster="failover"可以不用写,因为默认就是failover。

  • Failfast Cluster
      快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。配置示例:
	<dubbo:service cluster="failfast" />

  或者:

	<dubbo:reference cluster="failfast" />

  cluster="failfast"和 把 cluster=“failover”、retries="0"是一样的效果,retries="0"就是不重试。

  • Failsafe Cluster
      失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。配置示例:
	<dubbo:service cluster="failsafe" />

  或者:

	<dubbo:reference cluster="failsafe" />
  • Failback Cluster
      失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。配置示例:
	<dubbo:service cluster="failback" />

  或者:

	<dubbo:reference cluster="failback" />
  • Forking Cluster
      并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。配置示例:
	

  或者:

	
  • Broadcast Cluster
      广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息。
  • 不同的配置级别
      服务端服务级别:
	<dubbo:service interface="..." loadbalance="roundrobin" />

  客户端服务级别:

<dubbo:reference interface="..." loadbalance="roundrobin" />

  服务端方法级别:

	<dubbo:service interface="..."> <dubbo:method name="..." loadbalance="roundrobin" />

  客户端方法级别:

	<dubbo:reference interface="..."> <dubbo:method name="..." loadbalance="roundrobin" />

2.5.2 负载均衡

  Dubbo负载均衡在客户端。
  Dubbo默认采用Random LoadBalance策略

  • 1、Random LoadBalance
      随机,按权重设置随机概率。
      在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
  • 2、RoundRobin LoadBalance
      轮循,按公约后的权重设置轮循比率。
      存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
  • 3、LeastActive LoadBalance
      最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
      使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
      每个服务维护一个活跃数计数器。当A机器开始处理请求,该计数器加1,此时A还未处理完成。若处理完毕则计数器减1。而B机器接受到请求后很快处理完毕。那么A、B的活跃数分别是1、0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使慢的机器A收到少的请求。
  • 4、ConsistentHash LoadBalance
      一致性Hash,相同参数的请求总是发到同一提供者。
      当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
      缺省只对第一个参数Hash,如果要修改,配置示例:
	<dubbo:parameter key="hash.arguments" value="0,1" />

  缺省用160份虚拟节点,如果要修改,配置示例:

	<dubbo:parameter key="hash.nodes" value="320" />

2.6 Monitor实现原理

  Consumer端在发起调用之前会先走filter链;provider端在接收到请求时也是先走filter链,然后才进行真正的业务逻辑处理。默认情况下,在consumer和provider的filter链中都会有Monitorfilter。

  • 1、MonitorFilter向DubboMonitor发送数据。
  • 2、DubboMonitor将数据进行聚合后(默认聚合1min中的统计数据)暂存到ConcurrentMap statisticsMap,然后使用一个含有3个线程(线程名字: DubboMonitorSendTimer)的线程池每隔1min钟,调用SimpleMonitorService遍历发送statisticsMap中的统计数据,每发送完毕一 个,就重置当前的Statistics的AtomicReference。
  • 3、SimpleMonitorService将这些聚合数据塞入BlockingQueue queue中 (队列大写为100000)。
  • 4、SimpleMonitorService使用一个后台线程(线程名为:DubboMonitorAsyncWriteLogThread)将queue中的数据写入文件(该线程以死循环的形式来写)。
  • 5、SimpleMonitorService还会使用一个含有1个线程(线程名字:DubboMonitorTimer)的线程池每隔5min,将文件中的统计数据画成图表。

三、Dubbo附加功能

3.1 服务分组

  当一个接口有多种实现时,可以用group区分。
  服务示例:

	<dubbo:service group="feedback" interface="com.xxx.IndexService" />
	<dubbo:service group="member" interface="com.xxx.IndexService" />

  示例:

	<dubbo:reference id="feedbackIndexService" group="feedback" 
		interface="com.xxx.IndexService" />

3.2 多版本

  当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
  可以按照以下的步骤进行版本迁移:

  1. 在低压力时间段,先升级一半提供者为新版本;
  2. 再将所有消费者升级为新版本;
  3. 然后将剩下的一半提供者升级为新版本。

  老版本服务提供者配置示例:

	<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" />

3.3 异步调用

  基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。
Dubbo基本概念_第8张图片

3.4 事件通知

  在调用之前、调用之后、出现异常时,会触发oninvoke、onreturn、onthrow三个事件,可以配置当事件发生时,通知哪个类的哪个方法 。
  服务消费者Callback配置示例:

<bean id ="demoCallback" class = "com.alibaba.dubbo.callback.implicit.NofifyImpl" />
<dubbo:reference id="demoService" 
	interface="com.alibaba.dubbo.callback.implicit.IDemoService" version="1.0.0" group="cn" >
<dubbo:method name="get" async="true" 
	onreturn = "demoCallback.onreturn" onthrow="demoCallback.onthrow" />
dubbo:reference>

  callback与async功能正交分解, async=true表示结果是否马上返回,onreturn表示是否需要回调。
  两者叠加存在以下几种组合情况 :

异步回调模式: async=true onreturn=“xxx”
同步回调模式: async=false onreturn=“xxx”
异步无回调 : async=true
同步无回调 : async=false

3.5 本地伪装

  本地伪装通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过Mock数据返回授权失败。
  在Spring配置文件中按以下方式配置:

<dubbo:service interface="com.foo.BarService" mock="true" />

<dubbo:service interface="com.foo.BarService" mock="com.foo.BarServiceMock" />

  如果服务的消费方经常需要try-catch捕获异常,如:

	Offer offer = null;
	try {
		offer = offerService.findOffer(offerId);
	} catch (RpcException e) {
		logger.error(e);
	}

  请考虑改为Mock实现,并在Mock实现中return null。如果只是想简单的忽略异常,在2.0.11以上版本可用:

	<dubbo:service interface="com.foo.BarService" mock="return null" />

3.6 令牌验证

  通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者,另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。图示:
Dubbo基本概念_第9张图片
  可以全局设置开启令牌验证:

	
	<dubbo:provider interface="com.foo.BarService" token="true" />
	
	<dubbo:provider interface="com.foo.BarService" token="123456" />

  也可在服务级别设置:

	
	<dubbo:service interface="com.foo.BarService" token="true" />
	
	<dubbo:service interface="com.foo.BarService" token="123456" />

  还可在协议级别设置:

	
	<dubbo:protocol name="dubbo" token="true" />
	
	<dubbo:protocol name="dubbo" token="123456" />

3.7 写入路由规则

  向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成。
  condition://:表示路由规则的类型,支持条件路由规则和脚本路由规则,可扩展,必填。
  0.0.0.0:表示对所有IP地址生效,如果只想对某个IP的生效,请填入具体IP,必填。
  com.foo.BarService:表示只对指定服务生效,必填。
  category=routers:表示该数据为动态配置类型,必填。
  dynamic=false:表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填。
  enabled=true:覆盖规则是否生效,可不填,缺省生效。
  force=false:当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路
由规则将自动失效,可不填,缺省为flase 。
  runtime=false:是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为true,需要注意设置会影响调用的性能,可不填,缺省为flase 。
  priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为
0 。
  rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11"):表示路由规则的内容,必填。

3.8 优雅停机

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

  • 服务提供方
      停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
  • 服务消费方
      停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
      然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
  • 设置方式
      设置优雅停机超时时间,缺省超时时间是10秒,如果超时则强制关闭。示例:
<dubbo:application ...>
<dubbo:parameter key="shutdown.timeout" value="60000" /> 
dubbo:application>

3.9 注册中心

Dubbo基本概念_第10张图片

3.9.1 流程说明

  服务提供者启动时:向/dubbo/com.foo.BarService/providers目录下写入自己的 URL地址。
  服务消费者启动时:订阅/dubbo/com.foo.BarService/providers目录下的提供者 URL地址。并向/dubbo/com.foo.BarService/consumers目录下写入自己的URL地址监控中心。
  启动时:订阅/dubbo/com.foo.BarService目录下的所有提供者和消费者URL地址。

  • 支持以下功能
      当提供者出现断电等异常停机时,注册中心能自动删除提供者信息。
      当注册中心重启时,能自动恢复注册数据,以及订阅请求。
      当会话过期时,能自动恢复注册数据,以及订阅请求:
      当设置时,记录失败注册和订阅请求,后台定时重试。可通过设置zookeeper登录信息。可通过设置zookeeper的根节点,不设置将使用无根树支持 * 号通配符,可订阅服务的所有分组和所有版本的提供者使用。

3.9.2 Dubbo注册中心分类

  Dubbo默认采用Zookeeper注册中心

  • Multicast注册中心
      Multicast注册中心不需要任何中心节点,只要广播地址,就能进行服务注册和发现。基于网络中组播传输实现;
  • Zookeeper注册中心
      基于分布式协调系统Zookeeper实现,采用Zookeeper的watch机制实现数据变更;
  • Redis注册中心
      基于Redis实现,采用key/Map存储,在key存储服务名和类型,Map中key存储服务URL,value服务过期时间。基于Redis的发布/订阅模式通知数据变更;
  • Simple注册中心

3.9.3 Dubbo注册中心的相关问题

  • 1、Dubbo的注册中心集群挂掉,发布者和订阅者之间还能通信么?
      可以的,启动Dubbo时,消费者会从zookeeper拉取注册的生产者的地址接口等数据,缓存在本地。
      每次调用时,按照本地存储的地址进行调用。
      注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务的提供者和消费者仍能通过本地缓存通讯。服务提供者无状态,任一台 宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;
      挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。
  • 2、注册中心挂了了,消费者还能调用服务者吗?
      注册中心对等集群,任意一台宕掉后,会自动切换到另一台。
      注册中心全部宕掉,服务提供者和消费者仍可以通过本地缓存通讯。
      服务提供者无状态,任一台宕机后,不影响使用。
      服务提供者全部宕机,服务消费者会无法使⽤用,并无限次重连等待服务者恢复。

3.10 Dubbo配置

3.10.1 Dubbo的核心配置及作用

Dubbo基本概念_第11张图片

3.10.2 Dubbo的配置优先级

Dubbo基本概念_第12张图片
  优先级从高到低:

JVM -D参数:当部署或启动应用时,可以重写配置,比如改变Dubbo协议端口。
XML:XML中的当前配置会重写dubbo.properties中的;
Properties:默认配置,仅仅作用域以上两者都没有配置时。

3.10.3 Dubbo的配置来源有几种,分别是什么

  4种:

JVM System Properties,-D参数;
Externalized Configuration,外部化配置;
ServiceConfig、ReferenceConfig等编程接口采集的配置;
本地配置文件dubbo.properties。

3.10.4 开发测试环境,想绕过注册中心如何配置

  xml配置示例:

	<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService" 
		url="dubbo://localhost:20890"/>

  -D配置示例:

	java -D com.alibaba.xxx.XxxService=dubbo://localhost:20890

  properties配置示例:

	java -D dubbo.resolve.file=xxx.properties
	com.alibaba.xxx.XxxService=dubbo://localhost:20890

3.10.5 Dubbo配置文件是如何加载到Spring中的

  Spring容器在启动的时候,会读取到Spring默认的一些schema以及Dubbo自定义的schema,每个schema都会对应一个自己的NamespaceHandler,NamespaceHandler里面通过BeanDefinitionParser来解析配置信息并转化为需要加载的bean对象。

四、Dubbo使用注意事项

4.1 最佳实践

  • 分包
      建议将服务接口,服务模型,服务异常等均放在API包中,因为服务模型及异常也是API的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。
      如果需要,也可以考虑在API包中放置一份Spring的引用配置,这样使用方,只需在Spring加载过程中引用此配置即可,配置建议放在模块的包目录下,以免冲突,如: com/alibaba/china/xxx/dubbo-reference.xml 。
  • 粒度
      服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo暂未提供分布式事务支持。
      服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。
      不建议使用过于抽象的通用接口,如: Map query(Map) ,这样的接口没有明确语义,会给后期维护带来不便。
  • 版本
      每个接口都应定义版本号,为后续不兼容升级提供可能,如:
      建议使用两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。
      当不兼容时,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。
  • 兼容性
      服务接口增加方法,或服务模型增加字段,可向后兼容,删除方法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。
  • 枚举值
      如果是完备集,可以用Enum ,比如: ENABLE , DISABLE 。
      如果是业务种类,以后明显会有类型增加,不建议用Enum,可以用String代替。
      如果是在返回值中用了Enum,并新增了Enum值,建议先升级服务消费方,这样服务提供方不会返回新值。
      如果是在传入参数中用了Enum,并新增了Enum值,建议先升级服务提供方,这样服务消费方不会传入新值。
  • 序列化
      服务参数及返回值建议使用POJO对象,即通过setter、getter方法表示属性的对象。
      服务参数及返回值不建议使用接口,因为数据模型抽象的意义不大,并且序列化需要接口实现类的元信息,并不能起到隐藏实现的意图。
      服务参数及返回值都必需是byValue的,而不能是byReference的,消费方和提供方的参数或返回值引用并不是同一个,只是值相同,Dubbo不支持引用远程对象。
  • 异常
      建议使用异常汇报错误,而不是返回错误码,异常信息能携带更多信息,以及语义更友好。如果担心性能问题,在必要时,可以通过override掉异常类的fillInStackTrace()方法为空方法,使其不拷贝栈信息。
      查询方法不建议抛出checked异常,否则调用方在查询时将过多的try…catch,并且不能进行有效处理。
      服务提供方不应将DAO或SQL等异常抛给消费方,应在服务实现中对消费方不关心的异常进行包装,否则可能出现消费方无法反序列化相应异常。
  • 调用
      不要只是因为是Dubbo调用,而把调用try…catch起来。try…catch应该加上合适的回滚边界上。
      对于输入参数的校验逻辑在Provider端要有。如有性能上的考虑,服务实现者可以考虑在API包上加上服务Stub类来完成检验。
  • Provider上尽量多配置Consumer端属性
      原因如下:
      作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等。
      在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值 。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
      Provider上尽量多配置Consumer端的属性,让Provider实现者一开始就思考Provider服务特点、服务质量的问题。
  • Provider上配置合理的Provider端属性
      Provider上可以配置的Provider端属性有:
  1. threads:服务线程池大小。
  2. executes:一个服务提供者并行执行请求上限,即当Provider对一个服务的并发调用到上限后,新调用会Wait,这个时候Consumer可能会超时。在方法上配置dubbo:method则并发限制针对方法,在接口上配置dubbo:service ,则并发限制针对服务。

4.2 使用建议

  • Dubbo服务划分
      1、服务划分目标:抽取系统中独立的业务模块服务化,按业务独立性进行垂直划分,抽象出基础服务层。
      2、子系统划分把控:合理划分,过细过粗都不行。
      3、注意事项:
  1. 表:避免出现A服务关联B服务的表的数据操作;服务一旦划分了,那么数据库即便没分开,也要当成db表分开了来进行编码;否则AB服务难以进行垂直拆库。
  2. 避免服务耦合度高,依赖调用;如果出现,考虑服务调优。
  3. 避免分布式事务,不要拆分过细。
  • Dubbo接口划分
      1、接口尽可能大粒度,接口中的方法不要以业务流程来,这个流程尽量在方法逻辑中调用,接口应代表一个完整的功能对外提供。
      2、接口应以业务为单位,业务相近的进行抽象,避免接口数量爆炸。
      3、参数先做校验,在传入接口。
      4、要做到在设计接口时,已经确定这个接口职责、预测调用频率。
  • 依赖
      web应用大致分为两层:biz和web,实际上biz可能由内部多个工程组成,这里biz只是一个抽象概念。impl依赖api和biz,web依赖impl和biz,没有其他依赖关系,严禁biz依赖api。关系:
    Dubbo基本概念_第13张图片
  • 分包
      biz-service、biz-api、biz-web。
      web依赖于api;service依赖于api;service和web没有依赖;controller是一个工程,service+dao是一个工程。
    Dubbo基本概念_第14张图片
      biz-service放converter、dao、service.impl、application、config、properties;
      biz-api放domain、enumeration、exception;
      biz-web放controller、config、properties;
      common放公共代码。
  • 事务
      如果仅仅是应用拆分,而没有数据库的拆分,那么仍可视为单机事务。
      如果数据库也进行了拆分,每个应用使用的表被放在相应机器的数据库中,那么需要考虑分布式事务问题。
      分布式事务的前提是多个数据库之间难以保证一致性,单一数据库本身的事务机制可以保证数据一致性。

五、相关问题

5.1 Dubbo支持哪些序列化方式?

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

5.2 Dubbo超时时间怎样设置?

  Dubbo超时时间设置有两种方式:

  • 1、服务提供者端设置超时时间,在Dubbo的用户文档中,推荐如果能在服务端多配置就尽量多配置,因为服务提供者比消费者更清楚自己提供的服务特性。
  • 2、服务消费者端设置超时时间,如果在消费者端设置了超时时间,以消费者端为主,即优先级更高。因为服务调用方设置超时时间控制性更灵活。如果消费方超时,服务端线程不会定制,会产生警告。

5.3 服务调用超时问题怎么解决?

  Dubbo在调用服务不成功时,默认是会重试两次的。

5.4 Dubbo在安全机制方面的做法

  Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。Dubbo还提供服务黑白名单,来控制服务所允许的调用方。

5.5 Dubbo支持服务降级吗?

  Dubbo2.2.0以上版本支持。

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

  服务失效踢出基于Zookeeper的临时节点原理。(服务机器会在zk上注册一个临时节点,服务失效则临时节点被删除)。

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

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

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

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

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

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

5.10 Dubbo服务暴露的过程

  Dubbo会在 Spring实例化完bean之后,在刷新容器最后一步发布ContextRefreshEvent事件的时候,通知实现了ApplicationListener的ServiceBean类进行回调onApplicationEvent事件方法,Dubbo会在这个方法中调用ServiceBean父类ServiceConfig的export方法,而该方法真正实现了服务的(异步或者非异步)发布。

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

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

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

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

5.13 Dubbo可以对结果进行缓存吗?

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

	<dubbo:reference cache="true" />

  其实比普通的配置文件就多了一个标签 cache=“true”。

5.14 Dubbo服务之间的调用是阻塞的吗?

  默认是同步等待结果阻塞的,支持异步调用。
  Dubbo是基于 NIO的非阻塞实现并行调用,客户端不不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个Future对象。异步调用流程图:
Dubbo基本概念_第15张图片

5.15 注册了多个同一样的服务,如果测试指定的某一个服务呢?

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

5.16 Dubbo和Dubbox之间的区别?

  Dubbox和Dubbo本质上没有区别,Dubbox扩展了Dubbo而已,以下扩展出来的功能:

  1. 支持 REST 风格远程调用(HTTP + JSON/XML);
  2. 支持基于Kryo和FST的Java高效序列化实现;
  3. 支持基于Jackson的JSON序列化;
  4. 支持基于嵌入式Tomcat的HTTP remoting体系;
  5. 升级Spring至3.x;
  6. 升级ZooKeeper客户端;
  7. 支持完全基于Java代码的Dubbo配置。

5.17 Dubbo对JDK版本的最低要求

  JDK1.6。

5.18 Dubbo服务调用默认是阻塞的吗

  默认是同步等待结果阻塞的,同时也支持异步调用。
  Dubbo是基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个Future对象。

5.19 IO线程池默认大小

  CPU个数+1。

5.20 Dubbo服务降级,失败重试怎么做?

  可以通过dubbo:reference中设置mock=“return null”。mock的值也可以修改为true,然后再跟接口同一个路径下实现一个Mock类,命名规则是“接口名称+Mock”后缀。然后在Mock类里实现自己的降级逻辑。

5.21 Dubbo用到了哪些设计模式?

  • 1、工厂模式
      Provider在export服务时,会调用ServiceConfig的export方法。ServiceConfig中有个字段:
	private static final Protocol protocol = 
		ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

  Dubbo里有很多这种代码。这也是一种工厂模式,只是实现类的获取采用了JDK SPI的机制。这么实现的优点是可扩展性强,想要扩展实现,只需要在classpath下增加个文件就可以了,代码零侵入。另外,像上面的Adaptive实现,可以做到调用时动态决定调用哪个实现,但是由于这种实现采用了动态代理,会造成代码调试比较麻烦,需要分析出实际调用的实现类。

  • 2、装饰器模式
      Dubbo在启动和调用阶段都大量使用了装饰器模式。以Provider提供的调用链为例,具体的调用链代码是在ProtocolFilterWrapper的buildInvokerChain完成的,具体是将注解中含有group=provider的Filter实现,按照order排序,最后的调用顺序是:EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter ->ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter ->ExceptionFilter。
      更确切地说,这里是装饰器和责任链模式的混合使用。例如,EchoFilter的作用是判断是否是回声测试请求,是的话直接返回内容,这是一种责任链的体现。而像ClassLoaderFilter则只是在主功能上添加了功能,更改当前线程的ClassLoader,这是典型的装饰器模式。
  • 3、观察者模式
      Dubbo的Provider启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时,采用了观察者模式,开启一个listener。注册中心会每5秒定时检查是否有服务更新,如果有更新,向该服务的提供者发送一个notify消息,provider接受到notify消息后,即运行NotifyListener的notify方法,执行监听器方法。
  • 4、动态代理模式
      Dubbo扩展JDK SPI的类ExtensionLoader的Adaptive实现是典型的动态代理实现。Dubbo需要灵活地控制实现类,即在调用阶段动态地根据参数决定调用哪个实现类,所以采用先生成代理类的方法,能够做到灵活的调用。生成代理类的代码是ExtensionLoader的createAdaptiveExtensionClassCode 方法。代理类的主要逻辑是,获取URL参数中指定参数的值作为获取实现类的key。

5.22 Dubbo可以对结果进行缓存吗?

  为了提高数据访问的速度。Dubbo 提供了声明式缓存,以减少用户加缓存的工作量:

	<dubbo:reference cache="true" />

  其实比普通的配置文件就多了一个标签cache=“true”。

5.23 Dubbo有哪几种配置方式?

  1)Spring配置方式;2)Java API配置方式。

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

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

5.25 在Provider上可以配置的Consumer端的属性有哪些?

  1)timeout:方法调用超时。
  2)retries:失败重试次数,默认重试2次。
  3)loadbalance:负载均衡算法,默认随机。
  4)actives 消费者端,最大并发调用限制。

5.26 Dubbo用到了哪些设计模式?

  Dubbo框架在初始化和通信过程中使用了多种设计模式,可灵活控制类加载、权限控制等功能。

  • 1、工厂模式
      Provider在export服务时,会调用ServiceConfig的export方法。ServiceConfig中有个字段:
	private static final Protocol protocol =
		ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

  Dubbo里有很多这种代码。这也是一种工厂模式,只是实现类的获取采用了JDKSPI的机制。这么实现的优点是可扩展性强,想要扩展实现,只需要在classpath下增加个文件就可以了,代码零侵入。另外,像上面的Adaptive实现,可以做到调用时动态决定调用哪个实现,但是由于这种实现采用了动态代理,会造成代码调试比较麻烦,需要分析出实际调用的实现类。

  • 2、装饰器模式
      Dubbo在启动和调用阶段都大量使用了装饰器模式。以Provider提供的调用链为例,具体的调用链代码是在ProtocolFilterWrapper的buildInvokerChain完成的,具体是将注解中含有group=provider的Filter实现,按照order排序,最后的调用顺序是:
EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter ->
ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter ->
ExceptionFilter

  更确切地说,这里是装饰器和责任链模式的混合使用。例如,EchoFilter的作用是判断是否是回声测试请求,是的话直接返回内容,这是一种责任链的体现。而像ClassLoaderFilter则只是在主功能上添加了功能,更改当前线程的ClassLoader,这是典型的装饰器模式。

  • 3、观察者模式
      Dubbo的Provider启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时,采用了观察者模式,开启一个listener。注册中心会每5秒定时检查是否有服务更新,如果有更新,向该服务的提供者发送一个notify消息,provider接受到notify消息后,即运行NotifyListener的notify方法,执行监听器方法。
  • 4、动态代理模式
      Dubbo扩展JDK SPI的类ExtensionLoader的Adaptive实现是典型的动态代理实现。Dubbo需要灵活地控制实现类,即在调用阶段动态地根据参数决定调用哪个实现类,所以采用先生成代理类的方法,能够做到灵活的调用。生成代理类的代码是ExtensionLoader的createAdaptiveExtensionClassCode方法。代理类的主要逻辑是,获取URL参数中指定参数的值作为获取实现类的key。

5.27 Dubbo中Zookeeper做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信吗?

  可以通信的,启动Dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用;任一一台宕机后,将会切换到另一台。注册中心全部宕机后,服务的提供者和消费者仍能本地缓存通讯。服务提供者无状态,任一台宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复。

你可能感兴趣的:(【Dubbo】,rpc,java,网络协议,Dubbo)