2021最新Java面经整理 | 框架篇(四)Dubbo框架

目录

一、Dubbo 的工作流程

二、Dubbo 的十层架构

三、Dubbo 常见配置

四、服务调用

1、提供者暴露一个服务的过程

2、消费者消费一个服务的过程

3、服务调用过程

五、Dubbo 的负载均衡机制

六、Dubbo 的容错机制

七、Dubbo 的服务降级

八、Dubbo 的动态代理策略

九、Dubbo 的SPI机制

十、Dubbo 的序列化协议

十一、Dubbo内置了哪几种服务容器

十二、Dubbo 和 Spring Cloud的区别

十三、其他问题

 

Dubbo是⼀个支持远程调用的分布式服务框架提供⾼性能和透明化的RPC远程服务调⽤⽅案,以及SOA服务治理方案

常见的重点问题,

透明远程调用    就像调用本地方法一样调用远程方法;只需简单配置,没有任何API侵入;

负载均衡机制    客户端(client)loadbalance;

容错重试机制    服务Mock数据,重试次数、超时机制等;

自动注册发现    注册中心基于接口名查询服务提 供者的IP地址,并且能够平滑添加或删除服务提供者;

性能日志监控    Monitor统计服务的调用次调和调用时间的监控中心;

服务治理中心    路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等手动配置。

自动治理中心    无,比如:熔断限流机制、自动权重调整等。

一、Dubbo 的工作流程

Java面经整理-Dubbo框架_spring

角色:

Provider: 暴露服务的服务提供方。

Consumer: 调用远程服务的服务消费方。

Registry: 服务注册与发现的注册中心。

Monitor: 统计服务的调用次调和调用时间的监控中心。

Container: 服务运行容器。

调用流程:

0. 服务容器负责启动,加载,运行服务提供者。

1. 服务提供者在启动时,向注册中心注册自己提供的服务。

2. 服务消费者在启动时,向注册中心订阅自己所需的服务。

3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

二、Dubbo 的十层架构

Dubbo框架设计一共划分了10个层,最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。

 Java面经整理-Dubbo框架_序列化_02

 

 

服务接口层(Service):实际业务逻辑,服务提供方和服务消费方对应的接口和实现。

配置层(Config):对外配置接口。

服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton。

服务注册层(Registry):负责服务地址的注册与发现,以服务URL为中心。

集群层(Cluster):封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务。

监控层(Monitor):RPC调用次数和调用时间监控。

远程调用层(Protocol):封将RPC的远程调用。

信息交换层(Exchange):封装请求响应模式,同步转异步。

网络传输层(Transport):抽象mina和netty为统一接口。

数据序列化层(Serialize):可复用的一些工具,扩展接口为Serialization等接口。

关于dubbo十层架构的一些理解,

在RPC中,Protocol是核心层,也就是只要有Protocol + Invoker + Exporter就可以完成非透明的RPC调用,然后在Invoker的主过程上Filter拦截点。

而Cluster是外围概念,所以Cluster的目的是将多个Invoker伪装成一个Invoker,这样其它人只要关注Protocol层Invoker即可,加上Cluster或者去掉Cluster对其它层都不会造成影响,因为只有一个提供者时,是不需要Cluster的。

Proxy层封装了所有接口的透明化代理,而在其它层都以Invoker为中心,只有到了暴露给用户使用时,才用Proxy将Invoker转成接口,或将接口实现转成Invoker,也就是去掉Proxy层RPC是可以Run的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。

而Remoting实现是Dubbo协议的实现,如果你选择RMI协议,整个Remoting都不会用上,Remoting内部再划为Transport传输层和Exchange信息交换层,Transport层只负责单向消息传输,是对Mina、Netty、Grizzly的抽象,它也可以扩展UDP传输,而Exchange层是在传输层之上封装了Request-Response语义。

Registry和Monitor实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。

三、Dubbo 常见配置

Java面经整理-Dubbo框架_序列化_03

 

 

provider.xml 示例,

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"

xmlns="http://www.springframework.org/schema/beans"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<dubbo:application name="demo-provider"/>

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

<dubbo:protocol name="dubbo" port="20890"/>

<bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>

</beans>

consumer.xml示例,

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"

xmlns="http://www.springframework.org/schema/beans"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<dubbo:application name="demo-consumer"/>

<dubbo:registry group="aaa" address="zookeeper://127.0.0.1:2181"/>

<dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.samples.basic.api.DemoService"/>

</beans>

四、服务调用

1、提供者暴露一个服务的过程

provider启动时,把想要提供的服务暴露在本地。

把服务暴露到远程。

启动netty服务,建立长连接。

连接到注册中心zk上。

监控zk上的消费服务。

Java面经整理-Dubbo框架_xml_04

 

 

注,本地暴露于远程暴露的区别:

本地暴露是暴露在本机JVM中,调用本地服务不需要网络通信。

远程暴露是将ip,端口等信息暴露给远程客户端,调用远程服务时需要网络通信。

2、消费者消费一个服务的过程

首先ReferenceConfig类的init方法调用Protocol的refer方法生成Invoker实例。然后把Invoker转为客户端需要的接口。

  Java面经整理-Dubbo框架_xml_05

 

 Java面经整理-Dubbo框架_xml_06

 

 

 

3、服务调用过程

Dubbo 服务调用过程比较复杂,包含众多步骤。比如发送请求、编解码、服务降级、过滤器链处理、序列化、线程派发以及响应请求等步骤。官方给出的服务调用过程图,如下,

 Java面经整理-Dubbo框架_xml_07

 

 

首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。至于响应的发送与接收过程,这张图中没有表现出来。

五、Dubbo 的负载均衡机制

1、Random LoadBalance,随机(默认的负载均衡策略)

RandomLoadBalance 是加权随机算法的具体实现,可以完全随机,也可以按权重设置随机概率。

2、RoundRobin LoadBalance,轮循

可以轮询和加权轮询。存在响应慢的提供者会累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

3、LeastActive LoadBalance,最少活跃调用数

活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求。此时应优先将请求分配给该服务提供者。

4、ConsistentHash LoadBalance,一致性Hash

一致性Hash算法,相同参数的请求一定分发到一个provider上去。provider挂掉的时候,会基于虚拟节点均匀分配剩余的流量,抖动不会太大。

六、Dubbo 的容错机制

容错机制指的是某中系统控制在一定范围的一种允许或包容犯错情况的发生,为了保证集群的整体可用,我们需要建立容错机制。

1、Failover cluster(默认)

失败自动切换,调用失败时,自动重试其他机器。通常用于读操作,但重试会带来更长延迟。

2、Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

3、Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

4、Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

5、Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。

七、Dubbo 的服务降级

降级的目的是为了保证核心服务可用。

降级可以有几个层面的分类:自动降级,人工降级;

按照功能可以分为:读服务降级和写服务降级。

  1. 对一些非核心服务进行人工降级,在大促之前通过降级开关关闭那些推荐内容,评价等对主流程序没有影响的功能
  2. 故障降级,比如调用的远程服务挂了,网络故障,或者RPC服务返回异常。那么可以直接降级,降级的方案比如设置默认值,采用兜底数据(系统推荐的行为广告挂了,可以提前准备静态页面做返回)等等
  3. 限流降级,在秒杀这种流量比较集中并且流量特别大的情况下,因为突发访问量特别大可能导致系统支撑不了。这个时候可以采用限流来限制访问量。当达到阈值时,后续的请求被降级,比如进入排队页面,比如跳转到错误页面(活动火爆,请稍后重试)。

Dubbo的降级方式:Mock,实现步骤如下,

  1. 在client端创建一个testmock类,实现对应的IGphello的接口(需要对哪个接口进行mock,就实现哪个)名称必须以mock结尾。
  2. 在client端的xml配置文件中,添加如下配置,增加一个mock属性指向创建的testmock。
  3. 模拟错误(设置timeout)模拟超时异常,运行测试代码即可访问到testmock这个类,当服务端故障解除以后,调用过程将恢复正常。

当服务器的压力比较大的时候,我们可以通过服务降级功能 临时屏蔽某个出错的非关键服务,并定义降级后的返回策略,屏蔽掉不重要的服务如广告服务等,来降低核心业务的压力。

mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

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

我们可以直接在Admin控制台来操作服务降级,服务消费者中的屏蔽相当于不发起远程调用。容错相当于对该服务的方法调用在失败后,再返回 null 值。

八、Dubbo 的动态代理策略

默认使用javassist动态字节码生成,创建代理类。也可以通过spi扩展机制配置自己的动态代理策略。

九、Dubbo 的SPI机制

SPI(Service Provider Interface),是一种服务发现机制。Dubbo SPI 源于 JDK SPI,并做了增强处理。简单理解:定义一个接口,并不用关心具体实现。其他人按照这个接口去实现内容。当需要接入别人的实现时,需要一种机制来保证他的内容被正确的加载运行,这就是 SPI。同时,可以在运行时,动态为接口替换实现类,增强了扩展性。

相比JDK 标准的 SPI,Dubbo SPI 主要增强了以下四点,

  1. 引入缓存,加快速度 
  2. jdk SPI仅通过接口类名获取所有实现,但是Duboo SPI可以根据接口类名和key值获取具体一个实现,不会一次性实例化所有实现,而只在需要时实例化。
  3. 扩展点加载失败的原因有更清楚的展示。
  4. 增加了 IoC 和 AOP 的支持。

十、Dubbo 的序列化协议

具体可以参照 Dubbo的序列化协议 。Dubbo 支持9中序列化协议,

dubbo://(推荐)

rmi://

hessian://

http://

webservice://

thrift://

memcached://

redis://

rest://

默认的是 dubbo 协议,使用单一长连接,NIO 异步通信,基于 hessian 作为序列化协议。适用于:传输数据量小,并发量高的场景(一般消费者服务远多于提供者服务)。

连接个数:单连接

连接方式:长连接

传输协议:TCP

传输方式:NIO异步传输

序列化:Hessian 二进制序列化

适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。

适用场景:常规远程服务方法调用

十一、Dubbo内置了哪几种服务容器

Spring Container

Jetty Container

Log4j Container

Dubbo 的服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。

十二、Dubbo 和 Spring Cloud的区别

1、通信方式不同

Dubbo 使用的是 RPC 通信,而 Spring Cloud 使用的是 HTTP RESTFul 方式。

2、组件生态不同

 

十三、其他问题

1、Dubbo是什么?

Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目。

2、为什么要用Dubbo?

因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性

使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。

下面这张图可以很清楚的诠释,最重要的一点是,分布式架构可以承受更大规模的并发流量。

 Java面经整理-Dubbo框架_序列化_08

 

 

 

下面是 Dubbo 的服务治理图。

 

 Java面经整理-Dubbo框架_xml_09

 

 

3、Dubbo 和 Spring Cloud 有什么区别?

两个没关联,如果硬要说区别,有以下几点。

1)通信方式不同

Dubbo 使用的是 RPC 通信,而 Spring Cloud 使用的是 HTTP RESTFul 方式。

2)组成部分不同

 

4、dubbo都支持什么协议,推荐用哪种?

dubbo://(推荐)

rmi://

hessian://

http://

webservice://

thrift://

memcached://

redis://

rest://

5、Dubbo需要 Web 容器吗?

不需要,如果硬要用 Web 容器,只会增加复杂性,也浪费资源。

6、Dubbo内置了哪几种服务容器?

Spring Container

Jetty Container

Log4j Container

Dubbo 的服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。

7、Dubbo里面有哪几种节点角色?

 Java面经整理-Dubbo框架_spring_10

 

 

8、画一画服务注册与发现的流程图

 Java面经整理-Dubbo框架_spring_11

 

 

 

该图来自 Dubbo 官网,供你参考,如果你说你熟悉 Dubbo, 面试官经常会让你画这个图,记好了。

9、Dubbo默认使用什么注册中心,还有别的选择吗?

推荐使用 Zookeeper 作为注册中心,还有 Redis、Multicast、Simple 注册中心,但不推荐。

10、Dubbo有哪几种配置方式?

1)Spring 配置方式

2)Java API 配置方式

11、Dubbo 核心的配置有哪些?

我曾经面试就遇到过面试官让你写这些配置,我也是蒙逼。。

 Java面经整理-Dubbo框架_spring_12

 

 

 

配置之间的关系见下图。

 Java面经整理-Dubbo框架_序列化_13

 

 

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

1)timeout:方法调用超时

2)retries:失败重试次数,默认重试 2 次

3)loadbalance:负载均衡算法,默认随机

4)actives 消费者端,最大并发调用限制

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

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

14、Dubbo推荐使用什么序列化框架,你知道的还有哪些?

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

15、Dubbo默认使用的是什么通信框架,还有别的选择吗?

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

16、Dubbo有哪几种集群容错方案,默认是哪种?

 Java面经整理-Dubbo框架_dubbo_14

 

 

 

17、Dubbo有哪几种负载均衡策略,默认是哪种?

 Java面经整理-Dubbo框架_apache_15

 

 

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

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

19、Dubbo支持服务多协议吗?

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

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

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

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

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

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

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

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

默认是同步等待结果阻塞的,支持异步调用。

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

异步调用流程图如下。

 Java面经整理-Dubbo框架_xml_16

 

 

24、Dubbo支持分布式事务吗?

目前暂时不支持,后续可能采用基于 JTA/XA 规范实现,如以图所示。

 Java面经整理-Dubbo框架_dubbo_17

 

 

25、Dubbo telnet 命令能做什么?

dubbo 通过 telnet 命令来进行服务治理,具体使用看这篇文章《dubbo服务调试管理实用命令》。

telnet localhost 8090

26、Dubbo支持服务降级吗?

Dubbo 2.2.0 以上版本支持。

27、Dubbo如何优雅停机?

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

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

服务失效踢出基于 Zookeeper 的临时节点原理。

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

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

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

读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器。

写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错。

31、Dubbo必须依赖的包有哪些?

Dubbo 必须依赖 JDK,其他为可选。

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

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

33、说说 Dubbo 服务暴露的过程。

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

34、Dubbo 停止维护了吗?

2014 年开始停止维护过几年,17 年开始重新维护,并进入了 Apache 项目。

35、Dubbo 和 Dubbox 有什么区别?

Dubbox 是继 Dubbo 停止维护后,当当网基于 Dubbo 做的一个扩展项目,如加了服务可 Restful 调用,更新了开源组件等。

36、你还了解别的分布式框架吗?

别的还有 Spring cloud、Facebook 的 Thrift、Twitter 的 Finagle 等。

37、Dubbo 能集成 Spring Boot 吗?

可以的,项目地址如下。

https://github.com/apache/incubator-dubbo-spring-boot-project

38、在使用过程中都遇到了些什么问题?

Dubbo 的设计目的是为了满足高并发小数据量的 rpc 调用,在大数据量下的性能表现并不好,建议使用 rmi 或 http 协议。

39、你读过 Dubbo 的源码吗?

要了解 Dubbo 就必须看其源码,了解其原理,花点时间看下吧,网上也有很多教程,后续有时间我也会在公众号上分享 Dubbo 的源码。

40、你觉得用 Dubbo 好还是 Spring Cloud 好?

扩展性的问题,没有好坏,只有适合不适合,不过我好像更倾向于使用 Dubbo, Spring Cloud 版本升级太快,组件更新替换太频繁,配置太繁琐,还有很多我觉得是没有 Dubbo 顺手的地方……