Dubbo学习笔记

文章详细介绍了Dubbo作为高性能JavaRPC框架的功能和工作原理,包括服务提供者、消费者、注册中心的概念,集群容错机制,如失败自动切换和快速失败,以及负载均衡策略。还涵盖了Dubbo的SPI机制、服务引入、监控器和各种协议的支持。此外,文章讨论了Dubbo的面试题,如容错模式和框架设计结构。

Dubbo笔记

Dubbo 概念

Apache Dubbo是一款高性能的Java RPC框架,其前身是阿里巴巴公司开源的一个高性能,轻量级的开源Java RPC框架。面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现

RPC

Remote Procedure Call Protocol

远程过程调用协议

RPC解析:客户端通过互联网调用远程服务器,不知道远程服务器具体实现,
只知道远程服务器提供了什么功能

优点

  • 数据安全性

Java中RPC框架比较多常见的有RMI、Hessian、GRPC、bRPC 、Dubbo

Dubbo的核心点

  • Provider 提供者,服务发布方
  • Consumer 消费者,调用服务方
  • Container Dubbo容器,依赖于Spring容器
  • Register 注册中心,当Container启动时把所有可以提供的服务列表上Registry中进行注册 [作用:告诉Consumer提供了什么服务和服务方在哪里]

Dubbo高可用

  • 集群容错
    • retries="2"来设置重试次数
  • 负责均衡
    • RandomLoadBalance 按照权重设置随机概率,无状态
    • RoundRobinLoadBalance 轮询,有状态
    • LeastActiveLoadBalance 最小活跃数随机,方法维度的统一服务调用数
    • ConsistenHashLoadBalance 一致性Hash

Dubbo的IO模型

NIO

Dubbo的原理

  • config配置层:对外配置接口,以ServiceConfig,ReferenceConfig为中心,可以直接初始化配置类,也可以通过Spring解析配置生成配置类
  • proxy服务代理层:服务接口透明代理,生产服务的客户端Stub和服务端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory
  • registry注册中心层:封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory,Registry,RegistryService

Dubbo SPI

SPI Service Provider Interface 是一种服务发现机制。SPI的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件

加载实现类。这样就可以在运行时,动态为接口替换实现类。

Java SPI的问题

  • 接口的所有实现类全部都需要加载并实例化
  • 无法根据参数来获取对应的实现类
  • 不能解决AOP、IOC的问题

Dubbo服务引入

Dubbo服务引用的时机有两个,第一个是在Spring容器中调用ReferenceBean的afterProoertiesSet方法时引用服务,第二个是在ReferenceBean对应的服务被注入到其他类中时引用。这两个引用服务的时机在于第一个饿汉式,第二个懒汉式。默认情况需要使用饿汉式,可通过配置dubbo:reference的init属性开启

Dubbo Monitor监听器

  • 1、启动容器,相当于在启动Dubbo的Provider
  • 2、启动后会去注册中心进行注册,注册所有可以提供的服务列表
  • 3、在Consumer启动后会去Register中获取服务列表和Provider的地址,进行订阅
  • 4、当Provider有修改后,注册中心会把消息推送给Consumer,用了观察者设计模式(又叫发布/订阅设计模式)
  • 5、根据获取到的Provider地址,真实调用Provider中功能
    • 在Consumer方使用了代理设计模式。创建一个Provider方类的一个代理对象。
    • 通过代理对象获取Provider中真实功能,起到Provider真实功能的作用。
  • 6、Consumer和Provider每隔1分钟向Monitor 发送统计信息,统计信息包含访问次数
    频率等。

Dubbo支持的注册中心

  • 1、Zookeeper 支持网络集群,但是依赖于Zookeeper的稳定性
  • 2、Redis注册中心 性能高,但是对服务器环境要求较高
  • 3、Multicast注册中心 去中心化,不需要额外安装,但是建议同机房(局域网)
  • 4、Simple注册中心 适用于测试,不支持集群

Dubbo支持的协议

  • Dubbo协议 官方推荐协议
    • 本质:使用NIO和线程池进行处理
    • 缺点:大文件传输时可能出现文件传输失败的问题
  • RMI协议 JDK提供的协议,远程调用协议
    • 缺点:偶尔连接失败
    • 优点:JDK原生,不需要进行额外配置
  • Hessian协议
    • 优点:基于Http协议,http请求支持
    • 缺点:需要额外导入jar,并在短链接时性能低

Dubbo面试题

Dubbo的容错机制
  • 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数
  • 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
  • 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
  • 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  • 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
  • 广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
Dubbo框架设计结构
  • 服务接口层:该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
  • 配置层:对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
  • 服务代理层:服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory。
  • 服务注册层:封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory、Registry和RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
  • 集群层:封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
  • 监控层:RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory、Monitor和MonitorService。
  • 远程调用层:封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
  • 信息交换层:封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
  • 网络传输层:抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
  • 数据序列化层:可复用的一些工具,扩展接口为Serialization、 ObjectInput、ObjectOutput和ThreadPool。
Dubbo提供的线程池
  • fixed:固定大小线程池,启动时建立线程,不关闭,一直持有。
  • cached:缓存线程池,空闲一分钟自动删除,需要时重建。
  • limited:可伸缩线程池,但池中的线程数只会增长不会收缩。(为避免收缩时突然来了大流量引起的性能问题)。
Dubbo注册中心挂了还可以继续通信么

可以,因为刚开始初始化的时候,消费者会将提供者的地址等信息拉取到本地缓存,所以注册中心挂了可以继续通信。

Dubbo 的分层

从大的范围来说,Dubbo 分为三层:Business 业务逻辑层由我们自己来提供接口和实现,还有一些配置信息。RPC 层就是真正的 RPC 调用的核心层,封装整个 RPC 的调用过程、负载均衡、集群容错、代理。Remoting 则是对网络传输协议和数据转换的封装。

划分到更细的层面,就是图中的10层模式,整个分层依赖由上至下,除 Business业务逻辑之外,其他的几层都是 SPI 机制。

分层具体描述
Businessservice业务逻辑层,提供接口实现
RPCconfig配置层,用于初始化配置信息
RPCproxy代理层,提供consumer和provider的代理
RPCregister服务注册层,封装服务地址的注册和发现
RPCcluster路由层,封装provider路由和负载均衡
RPCmonitor监控层,提供RPC调用时间和次数监控
RPCprotocol远程调用层,封装RPC调用
Remotingexchange信息交换层,用于封装请求响应模式,同步转异步
Remotingtransport网络传输层,对netty和mina的封装
Remotingserialize序列化层,提供数据的序列化和反序列化
Dubbo的工作原理

1、服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务;

2、register 根据服务订阅关系,返回 provider 信息到 consumer,同时 consumer 会把 provider 信息缓存到本地。如果信息有变更,consumer 会收到来自 register 的推送;

3、consumer 生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向 monitor 记录接口的调用次数和时间信息;

4、拿到代理对象之后,consumer 通过代理对象发起接口调用;

5、provider 收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现。

为什么要通过代理对象通信

主要是为了实现接口的透明代理,封装调用细节,让用户可以像调用本地方法一样调用远程方法,同时还可以通过代理实现一些其他的策略,比如:

  • 调用的负载均衡策略;
  • 调用失败、超时、降级和容错机制;
  • 做一些过滤操作,比如加入缓存、mock 数据;
  • 接口调用数据统计。
说说服务暴露的流程
  • 在容器启动的时候,通过 ServiceConfig 解析标签,创建 dubbo 标签解析器来解析 dubbo 的标签。容器创建完成之后,触发 ContextRefreshEvent 事件回调开始暴露服务;
  • 通过 ProxyFactory 获取到 invoker。invoker 包含了需要执行的方法的对象信息和具体的 URL 地址;
  • 再通过 DubboProtocol 的实现把包装后的 invoker 转换成 exporter,然后启动服务器 server,监听端口;
  • 最后 RegistryProtocol 保存 URL 地址和 invoker 的映射关系,同时注册到服务中心。

容器启动 —> 解析配置文件 —> 触发ContextRefreshEvent —> 创建invoker —> 转换exporter —> 开启server —> 服务中心注册

服务引用的流程

服务暴露之后,客户端就要引用服务,然后才是调用的过程。

  • 首先,客户端根据配置文件信息从注册中心订阅服务;
  • 之后,DubboProtocol 根据订阅的得到 provider 地址和接口信息连接到服务端 server,开启客户端 client,然后创建 invoker;
  • invoker 创建完成之后,通过 invoker 为服务接口生成代理对象。这个代理对象用于远程调用 provider,服务的引用就完成了。

容器启动 —> 订阅服务 —> 开启client —> 创建invoker —> 创建代理对象

有哪些负载均衡策略
  • 加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了;
  • 最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求;
  • 一致性 hash:通过 hash 算法,把 provider 的 invoke 和随机节点生成 hash,并将这个 hash 投射到 [0, 2^32 - 1] 的圆环上。查询的时候根据 key 进行 md5 然后进行 hash。得到第一个节点的值大于等于当前 hash 的 invoker。
  • 加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求。
集群容错方式有哪些
  • Failover Cluster 失败自动切换:Dubbo 的默认容错方案,当调用失败时自动切换到其他可用的节点。具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为1也就是只调用一次;
  • Failback Cluster 快速失败:在调用失败,记录日志和调用信息,然后返回空结果给 consumer,并且通过定时任务每隔5秒对失败的调用进行重试;
  • Failfast Cluster 失败自动恢复:只会调用一次,失败后立刻抛出异常;
  • Failsafe Cluster 失败安全:调用出现异常,记录日志不抛出,返回空结果;
  • Forking Cluster 并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个 provider,结果保存到阻塞队列,只要有一个 provider 成功返回了结果,就会立刻返回结果;
  • Broadcast Cluster 广播模式:逐个调用每个 provider,如果其中一台报错,在循环调用结束后,抛出异常。
了解 Dubbo SPI 机制吗

SPI 全称为 Service Provider Interface,是一种服务发现机制。本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类,这样可以在运行时,动态为接口替换实现类。

Dubbo 也正是通过 SPI 机制实现了众多的扩展功能,而且 Dubbo 没有使用 Java 原生的 SPI 机制,而是对其进行了增强和改进。

SPI 在 Dubbo 应用很多,包括协议扩展、集群扩展、路由扩展、序列化扩展等等。
使用方式可以在 META-INF/dubbo 目录下配置:

key=com.xxx.value

然后通过 Dubbo 的 ExtensionLoader 按照指定的 key 加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值