序言:
文章内容输出来源:拉勾教育Java高薪训练营。
本篇文章是学习课程中的一部分课后笔记
一、简介
1、dubbo概述
- Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
- 三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现
2、dubbo 处理流程
![](https://img.haomeiwen.com/i6223031/fdfbe17835916f3b.png)
节点说明:
![](https://img.haomeiwen.com/i6223031/56f8a4ae7825a5d3.png)
调用过程:
1.服务提供者在服务容器启动时,向注册中心注册自己提供的服务;
2.服务消费者在启动时,向注册中心订阅自己所需的服务;
3.注册中心返回服务提供者地址列表给消费者如果有变更 注册中心会基于长连接推送变更数据给消费者;
4.服务消费者从提供者地址列表中基于软负载均衡算法选一台提供者进行调用,如果调用失败,则重新选择一台;
5.服务提供者和消费者 在内存中的调用次数和调用时间定时每分钟发送给监控中心;
二、dubbo高级实战
1、SPI
- SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。
它就是一种动态替换发现的机制。
使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。
![](https://img.haomeiwen.com/i6223031/cf870d2df599f587.png)
2、SPI遵循约定
- 1、当服务提供者提供了接口的一种具体实现后,在META-INF/services目录下创建一个以接口全限定名为命名的文件,内容为实现类的全限定名;
- 2、接口实现类所在的jar包放在主程序的classpath中;
- 3、主程序通过java.util.ServiceLoader动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
- 4、SPI的实现类必须携带一个无参构造方法;
3、dubbo中的SPI
-
dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。
比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的所有已经实现好的扩展点。 -
Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性Hash),缺省为random随机调用。
默认提供的负载均衡策略.png
-
dubbo自己做SPI的目的
dubbo的spi目的.png
4、dubbo SPI中的Adaptive功能
- 主要解决的问题是如何动态的选择具体的扩展点。
通过getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的)
5、dubbo的Filter机制
- 为服务提供方和服务消费方调用过程进行拦截设计的,每次远程方法执行,该拦截都会被执行。
这样就为开发者提供了非常方便的扩展性,比如为dubbo接口实现ip白名单功能、监控功能 、日志记录等。
6、dubbo异步调用
-
这种方式主要应用于提供者接口响应耗时明显,消费者端可以利用调用接口的时间去做一些其他的接口调用,利用 Future 模式来异步等
待和获取结果即可。 目前这种方式可以通过XML的方式进行引入。 -
异步调用特殊说明
请确保dubbo的版本在2.5.4及以后的版本使用。 原因在于在2.5.3
及之前的版本使用的时候,会出现异步状态传递问题。
问题:
比如我们的服务调用关系是 A -> B -> C , 这时候如果A向B发起了异步请求,在错误的版本时,B向C发起的请求也会连带的产生异步请求。这是因为在底层实现层面,他是通过RPCContext中的attachment 实现的。在A向B发起异步请求时,会在 attachment 中增加一个异步标示字段来表明异步等待结果。
B在接受到A中的请求时,会通过该字段来判断是否是异步处理。但是由于值传递问题,B向C发起时同样会将该值进行传递,导致C误以为需要异步结果,导致返回空。
7、dubbo中线程池
- 目前已知的线程池模型有两个和java中的相互对应:
1、fix: 表示创建固定大小的线程池。也是Dubbo默认的使用方式,默认创建的执行线程数为200,并且是没有任何等待队列的。所以在极端的情况下可能会存在问题,比如某个操作大量执行时,可能存在堵塞的情况。
2、cache: 创建非固定大小的线程池,当线程不足时,会自动创建新的线程。但是使用这种的时候需要注意,如果突然有高TPS的请求过来,方法没有及时完成,则会造成大量的线程创建,对系统的CPU和负载都是压力,执行越多反而会拖慢整个系统。
8、路由规则
-
路由是决定一次请求中需要发往目标机器的重要判断,通过对其控制可以决定请求的目标机器。可以通过创建这样的规则来决定一个请求会交给哪些服务器去处理。
-
规则详解
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("route://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11")));
![](https://img.haomeiwen.com/i6223031/3b073152305cfb8b.png)
9、服务动态降级
-
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务有策略的降低服务级别,以释放服务器资源,保证核心任务的正常运行。
-
降级原因:
防止分布式服务发生雪崩效应,什么是雪崩?就是蝴蝶效应,当一个请
求发生超时,一直等待着服务响应,那么在高并发情况下,很多请求都是因为这样一直等着响应,直到服务资源耗尽产生宕机,而宕机之后会导致分布式其他服务调用该宕机的服务也会出现资源耗尽宕机,
这样下去将导致整个分布式服务都瘫痪,这就是雪崩。 -
dubbo 服务降级实现方式
-
1、整合 hystrix
-
2、java代码 动态写入配置中心
java降级.png
-
3、在 dubbo 管理控制台配置服务降级
降级策略.png
-
4、指定返回简单值或者null
-
<dubbo:reference id="xxService" check="false" interface="com.xx.XxService"
timeout="3000" mock="return null" />
<dubbo:reference id="xxService2" check="false" interface="com.xx.XxService2"
timeout="3000" mock="return 1234" />
如果是标注 则使用@Reference(mock="return null")
@Reference(mock="return 简单值") @Reference(mock="force:return null")
三、dubbo整体架构
![](https://img.haomeiwen.com/i6223031/022379a8dc26a1a1.png)
-
图例说明:
1、图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
2、图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。
3、图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。
4、图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。
5、Dubbo源码整体设计与调用链路十分相似。只不过这里可以看到接口的一些具体实现以及左侧也有更为详细的层次划分。 -
分层介绍:
-
service 业务层,包括我们的业务代码,比如接口实现类直接面向开发者RPC层远程过程调用层;
-
config 配置层,对外提供配置以ServiceConfig ReferenceConfig 为核心,可以直接初始化配置类也可以解析配置文件生成;
-
proxy 服务代理层 ,无论是生产者,还是消费者,框架都会产生一个代理类,整个过程对上层透明就是业务层对远程调用无感;
-
registry 注册中心层,封装服务地址的注册与发现 ,以服务的URL为中心;
-
cluster 路由层 (集群容错层) ,提供了多个提供者的路由和负载均衡 ,并且它桥接注册中心以Invoker为核心;
-
monitor 监控层, RPC调用相关的信息如调用次数成功失败的情况调用时间等在这一层完成;
-
protocol 远程调用层,封装RPC调用无论是服务的暴露还是服务的引用都是在Protocol中,作为主功能入口负责Invoker的整个生命周期 ,Dubbo中所有的模型都向Invoker靠拢;
-
Remoting层 远程数据传输层;
-
exchange 信息交换层 ,封装请求和响应的模式如把请求由同步转换成异步;
-
transport 网络传输层,统一网络传输的接口比如netty和mina统一为一个网络传输接口;
-
serialize 数据序列化层,负责管理整个框架中的数据传输的序列化 和反序列化;
-
网友评论