Dubbo原理解析(非常透彻)
一.概述
dubbo是一款经典的rpc框架,用来远程调用服务的。
dubbo的作用:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 服务自动注册和发现。
- 自定义序列化协议
Dubbo 架构中的核心角色有哪些?
- Container: 服务运行容器,负责加载、运行服务提供者。必须。
- Provider: 暴露服务的服务提供方,会向注册中心注册自己提供的服务。必须。
- Consumer: 调用远程服务的服务消费方,会向注册中心订阅自己所需的服务。必须。
- Registry: 服务注册与发现的注册中心。注册中心会返回服务提供者地址列表给消费者。非必须。
- Monitor: 统计服务的调用次数和调用时间的监控中心。服务消费者和提供者会定时发送统计数据到监控中心。非必须。
Dubbo 中的 Invoker 概念了解么?
-
Invoker
是 Dubbo 领域模型中非常重要的一个概念,你如果阅读过 Dubbo 源码的话,你会无数次看到这玩意。就比如下面我要说的负载均衡这块的源码中就有大量Invoker
的身影。 -
简单来说,
Invoker
就是 Dubbo 对远程调用的抽象。分为2种:- 服务提供
Invoker
- 服务消费
Invoker
- 服务提供
- 我们需要调用一个远程方法,我们需要动态代理来屏蔽远程调用的细节吧!我们屏蔽掉的这些细节就依赖对应的
Invoker
实现,Invoker
实现了真正的远程服务调用
Dobbo的分层架构(工作原理)
- Service业务层:就是我们写代码的层,我们使用rpc只需要关注该层就行,主要是定义接口和实现类。
- config 配置层:Dubbo 相关的配置。支持代码配置,同时也支持基于 Spring 来做配置,以
ServiceConfig
,ReferenceConfig
为中心 - proxy 服务代理层:调用远程方法像调用本地的方法一样简单的一个关键,真实调用过程依赖代理类,以
ServiceProxy
为中心。 - registry 注册中心层:封装服务地址的注册与发现。
- cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以
Invoker
为中心。 - monitor 监控层:RPC 调用次数和调用时间监控,以
Statistics
为中心。 - protocol 远程调用层:封装 RPC 调用,以
Invocation
,Result
为中心。 - exchange 信息交换层:封装请求响应模式,同步转异步,以
Request
,Response
为中心。 - transport 网络传输层:抽象 mina 和 netty 为统一接口,以
Message
为中心。 - serialize 数据序列化层 :对需要在网络传输的数据进行序列化。
二.SPI
Dubbo 的 SPI 机制了解么?
- SPI(Service Provider Interface) 机制被大量用在开源项目中(比如Dubbo,SpringBoot…),它可以帮助我们进行功能扩展。
- SPI 的具体原理是这样的:我们将接口的实现类放在配置文件中,我们在程序运行过程中读取配置文件,通过反射加载实现类。这样,我们可以在运行的时候,动态替换接口的实现类。
- 一些配置类就可以使用SPI进行加载,如果我们需要进行扩展,就自定义类放在指定文件夹下。
- Java 本身就提供了 SPI 机制的实现。不过,Dubbo 没有直接用,而是对 Java 原生的 SPI 机制进行了增强,以便更好满足自己的需求。
为什么 Dubbo 不用 JDK 的 SPI,而是要自己实现?
- 因为 Java SPI 在查找扩展实现类的时候遍历 SPI 的配置文件并且将实现类全部实例化,假设一个实现类初始化过程比较消耗资源且耗时,但是你的代码里面又用不上它,这就产生了资源的浪费。
- 因此 Dubbo 就自己实现了一个 SPI,给每个实现类配了个名字,通过名字去文件里面找到对应的实现类全限定名然后加载实例化,按需加载。
如果想深入研究Java SPI:请看一位大佬写的文章:SPI源码分析
如何扩展 Dubbo 中的默认实现?
- 比如说我们想要实现自己的负载均衡策略,我们创建对应的实现类
XxxLoadBalance
实现LoadBalance
接口或者AbstractLoadBalance
类。 - 我们将这个是实现类的路径写入到
resources
目录下的META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance
文件中即可。
public class XxxLoadBalance implements LoadBalance { public <T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException { // ... } }