《2021最新Java面试题全集-2021年第二版》不断更新完善!

    

第二十六章 DubboSpring Cloud Alibaba

1:Dubbo 的核心功能?

主要就是如下 3 个核心功能:

_   Remoting 网络通信框架,提供对多种 NIO 框架抽象封装,包括同步转异步请求-响应模式的信息交换方式。

_   Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。

_   Registry:服务注册,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

 

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

流程说明:

file

 

_   Provider(提供者)绑定指定端口并启动服务

_   提供者连接注册中心,并发本机 IP、端口、应用信息和提供服务信息发送至注册中心存储

_   Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心

_   注册中心根据 消费者 所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。

_   Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。

_   Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer 设计的原因:

_   Consumer Provider 解偶,双方都可以横向增减节点数。

_   注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台

_   去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用

_   服务提供者无状态,任意一台宕掉后,不影响使用

 

3:Dubbo 的架构设计

file

 

Dubbo 框架设计一共划分了 10 个层:

_   服务接口层( Service :该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。

_   配置层( Config :对外配置接口,以 ServiceConfig ReferenceConfig 为中心。

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

_   服务注册层( Registry :封装服务地址的注册与发现,以服务 URL为中心。

_   路由层( Cluster :封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心。

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

_   远程调用层( Protocol :封将 RPC 调用,以 Invocation Result为中心,扩展接口为 Protocol Invoker Exporter

_   信息交换层( Exchange :封装请求响应模式,同步转异步,以Request Response 为中心。

_   网络传输层( Transport :抽象 mina netty 为统一接口,以Message 为中心。

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

 

4:Dubbo 的服务调用流程?

 

file

 

5:Dubbo 的核心组件?

file

 

6:Dubbo 支持哪些协议,每种协议的应用场景,优缺点?

_   dubbo 单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。传输协议 TCP,异步, Hessian 序列化;

_   rmi 采用 JDK 标准的 rmi 协议实现,传输参数和返回参数对象需要实现 Serializable 接口,使用 java 标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议 TCP 多个短连接, TCP 协议传输,同步传输,适用常规的远程服务调用和rmi 互操作。在依赖低版本的 Common-Collections包, java 序列化存在安全漏洞;

_   webservice 基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言调用;

_   http 基于 Http 表单提交的远程调用协议,使用 Spring HttpInvoke 实现。多个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器 JS 调用;

_   hessian 集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务, Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传输, Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件;

_   memcache 基于 memcached 实现的 RPC 协议

_   Redis 基于 Redis 实现的 RPC 协议

 

7:为什么需要服务治理?

file

_   过多的服务 URL 配置困难

_   负载均衡分配节点压力过大的情况下,也需要部署集群,服务依赖混乱,启动顺序不清晰

_   过多服务导致性能指标分析难度较大,需要监控

 

8:Dubbo 的注册中心集群挂掉,发布者和订阅者之间还能通信么?

可以的,启动 dubbo 时,消费者会从 zookeeper 拉取注册的生产者的地址接口等数据,缓存在本地。

每次调用时,按照本地存储的地址进行调用。

 

9:Dubbo 提供了哪些负载均衡策略?

_   Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞率高,调用次数越多,分布越均匀;

_   RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问题;_ LeastActive LoadBalance: 最少活跃调用策略,解决慢提供者接收更少的请求;

_   ConstantHash LoadBalance: 一致性 Hash 策略,使相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动;

_   缺省时为 Random 随机调用

 

10:Dubbo 的容错方案有哪些?

_Failover Cluster

失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。

_Failfast Cluster

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

_Failsafe Cluster

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

_Failback Cluster

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

_Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。

_Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息

 

 

11:Dubbo Monitor 实现原理?

Consumer 端在发起调用之前会先走 filter 链;Provider 端在接收到请求时也是 先走 filter 链,然后才进行真正的业务逻辑处理。

默认情况下,在 consumerproviderfilter链中都会有Monitorfilter

1MonitorFilter DubboMonitor 发送数据

2DubboMonitor 将数据进行聚合后(默认聚合 1min 中的统计数据)暂存到 ConcurrentMap<Statistics, AtomicReference> statisticsMap

然后使用一个 含有 3 个线程(线程名字:DubboMonitorSendTimer)的线程池每隔 1min 钟, 调用 SimpleMonitorService 遍历发送 statisticsMap 中的统计数据,每发送完毕一个,就重置当前的StatisticsAtomicReference

3SimpleMonitorService 将这些聚合数据塞入 BlockingQueue queue

4SimpleMonitorService 使用一个后台线程将 queue 中的数据写入文件(该线程以 死循环的形式来写)

5SimpleMonitorService 还会使用一个含有 1 个线程的线程池每隔 5min 钟,将文件中的统计数据画成图表

 

12:Dubbo 用到哪些设计模式?

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

1:工厂模式

Provider export 服务时,会调用 ServiceConfig export 方法。ServiceConfig 中有个字段,获取协议对象:

private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtensi on();

 

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

 

13:Dubbo SPI Java SPI 区别?

JDK SPI

JDK 标准的 SPI 会一次性加载所有的扩展实现,如果有的扩展很耗时,但 也没用上,很浪费资源。

 

DUBBO SPI

(1)  Dubbo 进行扩展,不需要改动 Dubbo 的源码

(2)  延迟加载,可以一次只加载自己想要加载的扩展实现

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

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

 

14:Dubbo 支持服务降级吗?

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

 

15:Dubbo 如何优雅停机?

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