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 {
// ...
}
}
三.Dubbo 的负载均衡策略
- RandomLoadBalance:随机。随机的选择一个。是Dubbo的默认负载均衡策略。(加权/不加权)
- RoundRobinLoadBalance:轮询。轮询选择一个。(加权/不加权)
- LeastActiveLoadBalance:最少活跃数。每个服务维护一个活跃数计数器。当A机器开始处理请求,该计数器加1,此时A还未处理完成。若处理完毕则计数器减1。而B机器接受到请求后很快处理完毕。那么A,B的活跃数分别是1,0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使慢的机器A收到少的请求。
- ConsistentHashLoadBalance:一致性哈希。相同参数的请求总是落在同一台机器上。
四.服务暴露,服务引用,服务调用过程
服务暴露:生成代理类,将信息注册到ZK
- 组装URL:Spring IOC 容器刷新完毕之后,会根据配置参数组装成 URL, 然后根据 URL 的参数来进行代理类的生成。
- 生成代理类:会通过
proxyFactory.getInvoker
,利用 javassist 来进行动态代理,封装真的实现类。 - 根据协议生成暴露对象(exporter):通过 URL 参数选择对应的协议来进行 protocol.export,默认是 Dubbo 协议。
- 自适应:代理类会根据 Invoker 里面的 URL 参数得知具体的协议,然后通过 Dubbo SPI 机制选择对应的实现类进行 export。
- 注册到ZK:将 export 得到的 exporter 存入一个 Map 中,供之后的远程调用查找,然后会向注册中心注册提供者的信息。
想要深究源码的小伙伴可以看一位大佬写的文章:服务暴露源码分析。
服务引用:获取远程调用的类,生成代理类。可以看作服务引用的逆过程。
- 组装URL:会根据配置参数组装成 URL, 然后根据 URL 的参数来进行代理类的生成。(2种时机)
- 饿汉式:饿汉式是通过实现 Spring 的
InitializingBean
接口中的afterPropertiesSet
方法,容器通过调用ReferenceBean
的afterPropertiesSet
方法时引入服务。(在Spring启动时,给所有的属性注入实现类,包含远程和本地的实现类) - 懒汉式:只有当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引入。
- 在应用的Spring Context初始化完成事件时触发,扫描所有的Bean,将Bean中带有@Reference注解的field获取到,然后创建field类型的代理对象,创建完成后,将代理对象set给此field。后续就通过该代理对象创建服务端连接,并发起调用。(dubbo默认)
- 饿汉式:饿汉式是通过实现 Spring 的
- 从ZK中获取需要的服务提供者的信息:得到Map。
- 根据协议解析传过来的exporter:
- 协议的不同,获取的路径也不同:本地,直接,从ZK。
- 生成代理类:供消费者使用Netty进行远程调用。invoker。
想要深究源码的小伙伴可以看一位大佬写的文章:服务引用源码分析。
服务调用:
- 服务调用是在生成代理对象后,使用Netty,生成Netty Client进行远程调用。Netty Server通过反射返回调用结果。
- 在调用之前,就会进行智能容错和负载均衡。
- 首先客户端调用接口的某个方法,实际调用的是代理类,代理类会通过 cluster 从 directory(invoker的集合) 中获取一堆 invokers(如果有一堆的话),然后进行 router 的过滤(其中看配置也会添加 mockInvoker 用于服务降级),然后再通过 SPI 得到 loadBalance 进行一波负载均衡。
补充:cluster 是什么?
- 一个中间层,为消费者屏蔽了服务提供者的情况,简化了消费者的使用。
- 它可以负责选择哪个invoker返回给调用者,比如选择一个 invoker ,调用出错了可以换一个等等。
想要深究源码的小伙伴可以看一位大佬写的文章:服务调用源码分析。
容错机制:先容错,再负载均衡。
- 首先在服务引入的时候,将多个远程调用都塞入 Directory 中,然后通过 Cluster 来封装这个目录,封装的同时提供各种容错功能,比如 FailOver、FailFast 等等,最终暴露给消费者的就是一个 invoker。
- 然后消费者调用的时候会目录里面得到 invoker 列表,当然会经过路由的过滤,得到这些 invokers 之后再由 loadBalance 来进行负载均衡选择一个 invoker,最终发起调用。
dubbo常见的容错机制
- Failover Cluster(默认)
- 失败自动切换,当出现失败,重试其它服务器。
- 通常用于读操作,但重试会带来更长延迟。
- Failfast Cluster
- 快速失败,只发起一次调用,失败立即报错。
- 通常用于非幂等性的写操作,比如新增记录。
- Failsafe Cluster
- 失败安全,出现异常时,直接忽略。
- 通常用于写入审计日志等操作。
- Failback Cluster
- 失败自动恢复,后台记录失败请求,定时重发。
- 通常用于消息通知操作。
- Forking Cluster
- 并行调用多个服务器,只要一个成功即返回。
- 通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
想要深究源码的小伙伴可以看一位大佬写的文章:dubbo智能容错源码分析
五.其他小问题
Dubbo 为什么默认用 Javassist?
- 很简单,就是快,且字节码生成方便。
- 其他常见的动态代理: JDK 的动态代理、ASM、cglib。
- ASM 比 Javassist 更快,但是没有快一个数量级,而Javassist 只需用字符串拼接就可以生成字节码,而 ASM 需要手工生成,成本较高,比较麻烦。
Dubbo 支持多种序列化方式?
- JDK 自带的序列化:不支持跨语言调用 ;性能差
- JSON:性能差
- ProtoBuf :支持跨语言
- hessian2(默认):支持跨语言
- Protostuff:支持跨语言
- Kryo:新引入的,只支持JAVA
- FST:新引入的,只支持JAVA
寄语:你所看到的惊艳,都曾被平庸历练
Dubbo原理解析(非常透彻)的更多相关文章
- Java进阶专题(二十六) 将近2万字的Dubbo原理解析,彻底搞懂dubbo
前言 前面我们研究了RPC的原理,市面上有很多基于RPC思想实现的框架,比如有Dubbo.今天就从Dubbo的SPI机制.服务注册与发现源码及网络通信过程去深入剖析下Dubbo. Dubbo架构 ...
- Java进阶专题(二十七) 将近2万字的Dubbo原理解析,彻底搞懂dubbo (下)
...接上文 服务发现 服务发现流程 整体duubo的服务消费原理 Dubbo 框架做服务消费也分为两大部分 , 第一步通过持有远程服务实例生成Invoker,这个Invoker 在客户端是核心的远程 ...
- 分布式服务框架dubbo原理解析(转)
libaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产品 ...
- 分布式服务框架dubbo原理解析 转
alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产 ...
- Dubbo原理解析-注册中心之Zookeeper协议注册中心
下面我们来看下开源dubbo推荐的业界成熟的zookeeper做为注册中心, zookeeper是hadoop的一个子项目是分布式系统的可靠协调者,他提供了配置维护,名字服务,分布式同步等服务.对于z ...
- 分布式服务框架dubbo原理解析
alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产 ...
- 【DUBBO】Dubbo原理解析-服务引用
服务引用是服务的消费方向注册中心订阅服务提供方提供的服务地址后向服务提供方引用服务的过程. 服务的应用方在spring的配置实例如下: <dubbo:referenceid="demo ...
- 【DUBBO】Dubbo原理解析-服务发布
转载:http://blog.csdn.net/quhongwei_zhanqiu/article/details/41651205 服务发布方在spring的配置文件中配置如下: <bean ...
- Dubbo原理解析-监控
Dubbo发布代码中,自带了一个简易的监控中心实现.对于一般的小业务这个监控中心应该能够满足需求,对于那些大业务量的大公司一般都会有自己的监控中心,更加丰富的功能如常用的报警短信通知等等.这章讲解分析 ...
随机推荐
- 初识python:hello world 仪式感
python print 函数(在python中,不区分 ' ' 和 " "): print('hello world') 或者 print("hello wrold& ...
- Centos 7 上 查看MySQL当前使用的配置文件my.cnf的方法
my.cnf是mysql启动时加载的配置文件,一般会放在mysql的安装目录中,用户也可以放在其他目录加载.总的来说,my.cnf类似与window中my.ini 使用locate my.cnf命令可 ...
- js 调用同级的 iframe 方法
有两个 iframe <iframe id="a"> <script> function food(a){ return a+1; } </scrip ...
- [ bootstrap ] 图片内容占用padding的范围,如何解决?
问题描述: 从效果图看到,图片内容占据了padding的范围,怎么解决呢? html代码 <div class="container"> <div class=& ...
- vue3.0+ts+setup语法糖props写法
写法一 import defaultImg from '@/assets/images/defaultImg.png' const props = defineProps({ src: { type: ...
- 移动端字体图标不显示的Bug
用16进制编码的字体图标在部分小米机型显示不正常. 测试机型:小米1,小米1s,小米2浏览器:微信6.1内置浏览器,QQ浏览器 5.7 X5内核字体图标:不显示svg图标:显示正常 以下来自额微信内置 ...
- XCTF-反序列化中_wakeup()函数
跳过_wakeup()魔法函数__wakeup(): 将在序列化之后立即被调用漏洞原理: 当反序列化字符串中,表示属性个数的值大于其真实值,则跳过__wakeup()执行 对于该题,先可以看到类xct ...
- 一键AI着色,黑白老照片画面瞬间鲜活
很多老照片或者电影受时代技术所限制,只能以黑白形式保存:经过编辑后的黑白视频和图片早已丢失彩色原图,这对于保存者来说都十分遗憾.如何能将单一乏味.陈旧斑驳的黑白照片变成鲜活亮丽的彩色照片,从照片中重新 ...
- Java集合-ArrayList源码分析
目录 1.结构特性 2.构造函数 3.成员变量 4.常用的成员方法 5.底层数组扩容原理 6.序列化原理 7.集合元素排序 8.迭代器的实现 9.总结 1.结构特性 Java ArrayList类使用 ...
- 【机器学习基础】无监督学习(1)——PCA
前面对半监督学习部分作了简单的介绍,这里开始了解有关无监督学习的部分,无监督学习内容稍微较多,本节主要介绍无监督学习中的PCA降维的基本原理和实现. PCA 0.无监督学习简介 相较于有监督学习和半监 ...