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 机制。

分层 具体 描述
Business service 业务逻辑层,提供接口实现
RPC config 配置层,用于初始化配置信息
RPC proxy 代理层,提供consumer和provider的代理
RPC register 服务注册层,封装服务地址的注册和发现
RPC cluster 路由层,封装provider路由和负载均衡
RPC monitor 监控层,提供RPC调用时间和次数监控
RPC protocol 远程调用层,封装RPC调用
Remoting exchange 信息交换层,用于封装请求响应模式,同步转异步
Remoting transport 网络传输层,对netty和mina的封装
Remoting serialize 序列化层,提供数据的序列化和反序列化

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 加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。

你可能感兴趣的:(dubbo,学习,笔记)