1.Dubbo
Dubbo是阿里开源的一款RPC框架,现在已经是Apache的顶级项目,Dubbo的设计定位是一款高性能的RPC框架,随着Dubbo的发展,Dubbo还提供了服务治理、服务监控、服务网关等功能,所以Dubbo现在已经不单单是一款RPC框架了,还是一个具有不错生态的服务框架,但是单论服务生态能力还是和Spring Cloud有所不足。
Object]&name=image.png&originHeight=348&originWidth=762&originalType=binary&ratio=1&rotation=0&showTitle=false&size=30014&status=done&style=none&taskId=u16447615-f9ab-46c1-92d2-c6551555157&title=&width=762)
2.Dubbo高级特性
2.1 负载均衡
Dubbo提供了集群的负载均衡的能力,负载策略也有多种,默认是Random随机策略
,而已支持开发者自定义扩展负载策略。
- `随机策略`:可以设置按照权重设置随机手段。
- `轮询策略`:轮询调度分配,但是存在慢调用集中问题。
- `最少活跃调用数策略`:在消费者端进行调用的统计然后维护一个列表,调用数相同则随机。
- `一致性Hash策略`:相同参数的请求总是发送到同一个服务端。
2.2 Timeout服务超时机制
Dubbo的服务提供方和消费方都可以独立配置RPC调用的超时时间,但是这样会造成一个问题,如果服务端和消费端配置的超时时间不一致,可能导致一些问题,例如重试造成的幂等问题等。
2.3 集群容灾策略
一旦RPC调用失败后,Dubbo会根据配置的容灾手段来处理:
- `故障转移`:调用失败,发起另一台服务器的重试;一般适用于读请求,可以设置重试的次数,默认2次。
- `快速失败`:调用失败不进行重试,而是立即抛异常失败,适用于一致性要求比较高的写场景。
- `最终故障恢复`:调用失败后将请求保存,后台线程定时去重试执行,实现最终成功。
- `并行调用`:RPC调用时一次性调用多台服务器,只要1个返回成功就算成功,适合实时性要求高的读业务,而且可以设置`forks = 3`来设置并行度,避免IO资源浪费。
- `广播调用`:广播的模式调用所有服务端,通过参数配置来控制失败的比率是否通过的判定。
2.4 服务降级
通过mock参数来指定降级的策略和返回值。
2.5 回调
服务提供方的接口支持回调方法的定义,服务消费方调用接口可以传入一段实现类逻辑,由服务方执行。
2.6 异步调用
就是通过返回CompletableFuture来实现异步调用,后续通过CompletableFuture提供的API来判断是否拿到返回值来后续处理逻辑。
2.7 RPC泛化调用
所谓泛化调用其实就是服务消费者端无需依赖服务端提供的接口,而是利用Dubbo提供的GenericService
来充当一个通用Service,可以在参数上配置服务方接口名。
2.8 Dubbo REST
如果消费者端没有依赖Dubbo但是也想用Dubbo的服务方的服务,可以通过REST的形式来调用Dubbo服务提供者的服务。
2.9 路由规则
路由规则的目的是在RPC调用前起到一个过滤目标服务器的作用。路由方式分为:条件路由、标签路由。
- `条件路由`:在Dubbo控制台可以配置路由规则,通过表达式进行条件的限制。
- `标签路由`:将多个服务提供者划分到一个组,相当于对服务进行打标。通过标签来对路由进行控制,这样可以实现一些蓝绿发布、灰度、AB等功能。
3.Dubbo的SPI
Dubbo有一个很棒的扩展设计就是Dubbo的SPI,Dubbo的许多功能例如Protocol协议、Filter过滤器、LoadBalance负载的功能都是基于Dubbo的SPI机制来实现的。Dubbo的SPI机制主要封装在一个叫ExtensionLoader
的类中,通过这个ExtensionLoader就可以来自动加载我们外部程序员定义的实现类。Dubbo的SPI机制,需要让开发者将具体的扩展文件放在META-INF/dubbo
这个目录下。
Dubbo的SPI为每个扩展点接口单独设置一个文件,文件名就是接口的全限定名。
Dubbo相比于JDK的SPI,支持别名
的功能,可以通过别名来获取某个扩展点的实现。
3.1 ExtensionLoader
这个类标识某一个接口的扩展点加载器,用来加载某个扩展点接口的具体实例。ExtensionLoader内部有一个ConcurrentHashMap用来保存某个扩展接口对应的ExtensionLoader实例。
需要扩展点的接口上需要加上@SPI
的注解。
Dubbo不使用JDK的SPI,可能是因为:1.JDK的SPI是一次性加载所有的实现类,没有懒加载的功能。2.JDK的SPI没有IOC和AOP的功能,功能太单一,没有属性注入和代理的功能。
4.Dubbo的IOC
- 根据当前类,找到这个类中的setter方法,进行setter属性注入。
- 分析setter方法的入参类型pt,然后截取setter方法名property。
- 调用objectFactory.getExtension(pt, property)方法得到一个对象,这个方法就会从spring容器或者Dubbo SPI机制得到一个对象,然后通过反射注入。
5.Dubbo的简单AOP
Dubbo实现了类似Spring的简单的AOP功能,利用Wrapper机制来实现代理。
6.@Activate注解
@Activate称之为自动激活扩展点
,主要的目的是让有多个扩展点实现类在不同场景激活的情况。这个注解可以使用在类上和方法上,这个注解有3个重要的属性:
group
:为扩展类指定分组,打一个标识,支持多个。value
:为扩展类指定一个value,也是一个标识,支持多个。order
:多个扩展实现类的加载顺序,序号越小优先级越高。
通过ExtensionLoader#getExtensionLoader()方法得到Loader,然后通过loader#getActivateExtension方法来得到具体的扩展点实现类,入参就是group值。
7.URL
Dubbo的服务暴露的本质就是将服务端提供的接口服务告诉给客户端或者注册中心怎么访问具体的服务,就是将服务的请求路径URL暴露出来。Dubbo的URL概念包括:
- protocol:请求的协议,包括http、dubbo、thrift、hessian等
- username、password:用户名、密码
- host、port:主机IP地址和端口号
- path:服务具体路径或者叫服务定位名
- parameter:请求参数键值对
8.服务暴露简单流程
Dubbo的服务暴露,狭义上可分为2个流程:本地服务暴露和远程服务暴露。
- Dubbo服务暴露的入口方法是ServiceBean中的
#export( )
方法。当SpringBoot容器启动完成之后,容器会发布一个启动完成事件Event,实现了ApplicationListener接口的类就会触发这个事件来做反应,这就会出发export方法进行服务暴露。 - 根据服务接口的参数,封装URL对象。
- 根据scope的配置来决定是否进行本地暴露,如果配置了本地暴露则将协议改成injvm,然后通过代理工厂生成Invoker,暴露服务。
- 根据scope的配置来决定是否进行远程暴露,如果支持,也是通过代理工厂生成Invoker,暴露服务并在注册中心注册,例如在zk中创建节点注册ip、port、接口名、参数等。注册后还需要watch节点,监听节点的变化情况。
- 启动对应的网络组件Netty,用以接收RPC网络请求。
8.1 本地暴露
!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)
、exportLocal(url)
,通过判断配置,如果配置为remote那么表示只暴露本地服务。
本地暴露会将url转换成injvm
协议的url,ip就是127.0.0.1。
8.2 远程暴露
!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)
,如果没有配置是LOCAL模式,那么就会暴露远程服务。
8.3 export
远程服务暴露的时候会判断服务导出类型,分为是否需要注册中心。
8.3.1 Registry类型的export / 注册中心类型
有注册中心的先创建注册中心,然后暴露服务,将服务元数据信息注册到注册中心上。
URL体现为registry://127.1.1.1:1234/xxxxxxxxx。
8.3.2 非Registry类型的export / 无注册中心类型
无注册中心模式也就是直接暴露
,默认dubbo协议。URL的体现就是dubbo://126.1.1.1:1234/com.demo.demoService?xxx=xxx