Dubbo

洪湖

3176字约11分钟

2024-04-20

1.Dubbo是什么?

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

其核心部分包含:

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

2. Dubbo和 Spring Cloud 有什么区别?

最大的区别:

  • Dubbo底层是使用Netty这样的NIO框架,是基于TCP协议传输的,配合以Hession序列化完成RPC通信;
  • 而SpringCloud是基于Http协议+rest接口调用远程过程的通信,相对来说,Http请求会有更大的报文,占的带宽也会更多。但是REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更为合适,至于注重通信速度还是方便灵活性,具体情况具体考虑。

模块区别:

  • Dubbo主要分为服务注册中心,服务提供者,服务消费者,还有管控中心;

  • 相比起Dubbo简单的四个模块,SpringCloud则是一个完整的分布式一站式框架,他有着一样的服务注册中心,服务提供者,服务消费者,管控台,断路器,分布式配置服务,消息总线,以及服务追踪等;

3. Dubbo核心组件有哪些?

image-20210829190835070

  • Provider:暴露服务的服务提供方
  • Consumer:调用远程服务消费方
  • Registry:服务注册与发现注册中心
  • Monitor:监控中心和访问调用统计
  • Container:服务运行容器

4. Dubbo都支持什么协议,推荐用哪种?

1、 Dubbo协议:Dubbo默认使用Dubbo协议。

  • 适合大并发小数据量的服务调用,以及服务消费者远大于提供者的情况
  • Hessian二进制序列化。
  • 缺点是不适合传送大数据包的服务。

2、rmi协议:采用JDK标准的rmi协议实现,传输参数和返回参数对象需要实现Serializable接口。使用java标准序列化机制,使用阻塞式短连接,传输数据包不限,消费者和提供者个数相当。

  • 多个短连接,TCP协议传输,同步传输,适用常规的远程服务调用和rmi互操作
  • 缺点:在依赖低版本的Common-Collections包,java反序列化存在安全漏洞,需升级commons-collections3 到3.2.2版本或commons-collections4到4.1版本。

3、 webservice协议:基于WebService的远程调用协议(Apache CXF的frontend-simple和transports-http)实现,提供和原生WebService的互操作多个短连接,基于HTTP传输,同步传输,适用系统集成和跨语言调用。

4、http协议:基于Http表单提交的远程调用协议,使用Spring的HttpInvoke实现。对传输数据包不限,传入参数大小混合,提供者个数多于消费者

  • 缺点是不支持传文件,只适用于同时给应用程序和浏览器JS调用

5、hessian:集成Hessian服务,基于底层Http通讯,采用Servlet暴露服务,Dubbo内嵌Jetty作为服务器实现,可与Hession服务互操作 通讯效率高于WebService和Java自带的序列化

  • 适用于传输大数据包(可传文件),提供者比消费者个数多,提供者压力较大

  • 缺点是参数及返回值需实现Serializable接口,自定义实现List、Map、Number、Date、Calendar等接口

6、thrift协议:对thrift原生协议的扩展添加了额外的头信息。使用较少,不支持传null值

7、memcache:基于memcached实现的RPC协议

8、redis:基于redis实现的RPC协议

5. Dubbo服务器注册与发现的流程?

  • 服务容器Container负责启动,加载,运行服务提供者。
  • 服务提供者Provider在启动时,向注册中心注册自己提供的服务。
  • 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。
  • 注册中心Registry返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者Consumer和提供者Provider,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心Monitor。

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

三种服务容器:

  • Spring Container
  • Jetty Container
  • Log4j Container

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

7. Dubbo负载均衡的作用?

将负载均衡功能实现在rpc客户端侧,以便能够随时适应外部的环境变化,更好地发挥硬件作用。而且客户端的负载均衡天然地就避免了单点问题。定制化的自有定制化的优势和劣势。

它可以从配置文件中指定,也可以在管理后台进行配置修改。

事实上,它支持 服务端服务/方法级别、客户端服务/方法级别 的负载均衡配置。

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

Dubbo提供了4种负载均衡实现:

  1. RandomLoadBalance:随机负载均衡。随机的选择一个。是Dubbo的默认负载均衡策略。
  2. RoundRobinLoadBalance:轮询负载均衡。轮询选择一个。
  3. LeastActiveLoadBalance:最少活跃调用数,相同活跃数的随机。活跃数指调用前后计数差。使慢的 Provider 收到更少请求,因为越慢的 Provider 的调用前后计数差会越大。
  4. ConsistentHashLoadBalance:一致性哈希负载均衡。相同参数的请求总是落在同一台机器上。

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

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

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

10. DubboMonitor 实现原理?

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

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

11. Dubbo有哪些注册中心?

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

12. Dubbo的集群容错方案有哪些?

  • Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。
  • Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
  • Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
  • Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  • Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2″ 来设置最大并行数。
  • Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息。

13. Dubbo超时设置有哪些方式?

Dubbo超时设置有两种方式:

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

14. Dubbo用到哪些设计模式?

1、工厂模式

Provider 在 export 服务时,会调用 ServiceConfig 的 export 方法。ServiceConfig中有个字段:

private static final Protocol protocol =
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtensi
on();
复制代码

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。