Dubbo 是一款高性能、轻量级的开源 RPC 框架,提供服务自动注册、自动发现等高效服务治理方案, 可以和 Spring 框架集成。
随着服务的发展,服务越来越多,因此服务之间的调用和依赖关系也越来越复杂,从而衍生出了SOA(面向服务的架构体系),对服务提供、服务调用、连接处理、序列化方式、服务发现、服务路由等进行封装的服务框架,于是乎,分布式系统服务治理框架就出现了,Dubbo也由此诞生。
Dubbo从大范围可分为三层,Business业务层,RPC层,Remoting层
1、Business业务层
主要用来提供接口和实现的一些配置信息
2、RPC层
核心层,主要用来封装整个RPC的调用过程、负载均衡、集群容错、代理和远程调用
3、Remoting层
主要用来对网络传输协议和数据转换的封装
默认是阻塞,但是可以异步调用,Dubbo是基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,因此多线程开销较小,异步调用的时候会返回一个future对象。
Dubbo容错方案 | 说明 |
---|---|
Failover Cluster | **(默认)**失败自动切换,自动重试其他服务器 |
Failback Cluster | 失败自动恢复,记录失败请求,定时重发 |
Failfast Cluster | 快速失败,立即报错,只发起一次调用 |
Failsafe Cluster | 失败安全,出现异常,直接忽略 |
Forking Cluster | 并行调用多个服务提供者,只要一次成功即可返回 |
Broadcast Cluster | 广播模式,逐步调用每一个provider,如果其中一台报错,调用结束之后,会抛出异常 |
SPI(service provider Interface)是一种服务发现机制,本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类,这样可以在运行时,动态为接口替换实现类。
对Dubbo进行扩展,包括协议扩展、集群扩展、路由扩展、序列化扩展等等,此时不需要改动Dubbo源码
延迟加载,可以一次只加载自己想要加载的扩展实现
Dubbo的扩展机制很好的支持第三方IOC容器,默认支持Spring bean
修改META-INF/dubbo目录下的配置,通过dubbo的ExtensionLoader按照指定的key加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。
key=com.XXX.value
1、首先需要有一个注册中心,这样consumer和provider才能去注册和订阅服务
2、需要负载均衡的机制解决consumer如何调用客户端,其中也包括容错、重试机制
3、需要通信协议和工具框架,比如说通过http协议通信,然后根据协议选择使用什么框架和工具来进行通信,此外,数据传输也需要考虑序列化等等因素。
4、还需要一些监控、配置管理页面的服务
一般推荐使用Zookeeper作为注册中心,Multicast,Redis一般不推荐使用。
Dubbo采用的是Netty框架通信,一般要通过代理对象通信。
Netty 是一个基于NIO的客户、服务器端编程框架,Netty提供异步的,事件驱动的网络应用程序框架和工具,可以快速开发高可用的客户端和服务器。Netty是基于NIO的,它封装了JDK的NIO,让我们使用起来更加方法灵活。
传统IO(BIO 同步并阻塞)
传统IO中,每创建一个连接都要创建一个线程来维护,极大地浪费资源和增加服务器的压力,即创建的线程如果不做任何处理就会造成不必要的线程开销。
BIO适用场景
- 用于连接数目比较小且固定的框架 在jdk1.4之前选择使用
NIO模型(同步非阻塞)
NIO模型中,服务端实现模式为每一个线程处理多个请求,即客户端发送的请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求处理,NIO有三大核心部分:channel(通道)、Buffer(缓冲区)、selecter(选择器)
NIO服务模式:使一个线程从某通道发送请求或者读取数据,但是它仅仅能得到目前可用的数据,若果是无用数据,将不会获取,也不会阻塞。
NIO适用场景
NIO方式适用于连接数目多且连接比较大的架构,例如:相册服务器,在jdk 1.7之前选择使用
NIO工作流程
BIO基于字节流和字符流进行操作,而NIO以块的方式处理数据,块处理效率比BIO高
BIO是阻塞的,NIO是非阻塞的
使用Dubbo在进行服务调用的时候,由于各种原因(网络时延、服务器宕机、并发过高),调用就会出现RpcException,导致调用失败。服务降级就是指在服务不可用时,可以返回默认值,避免异常影响主业务的处理。
dubbo官网中使用一个mock配置,是实现服务降级。
服务提供方接口:
/**接口定义*/
public interface StudentService {
public void doSomething1();
public String doSomething2(String str);
}
/**实现类*/
public class StudentServiceImpl implements StudentService {
public void doSomething1() {
System.out.println("service invoke: doSomething1");
}
public String doSomething2(String str) {
System.out.println("service invoke: doSomething2 ," + str);
return "service invoke: doSomething2";
}
}
服务提供方dubbo.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="hello-world-app" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:service interface="com.sun.service.StudentService" ref="StudentServiceImpl" timeout="10000" />
<bean id="StudentServiceImpl" class="com.sun.serviceimpl.StudentServiceImpl" />
beans>
服务调用方:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbo-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:reference id="StudentService" interface="com.sun.service.StudentService" timeout="10000" check="false" mock="return null">
dubbo:reference>
beans>
测试在调用端调用服务两个方法,当服务端正常启动时,程序获得正常返回值;当服务提供方出现异常,调用方依然正常运行,调用doSomething2获取返回值时null。
上面在**dubbuo:reference 中配置mock=“retrun null” 的配置**,在服务降级时会对service中的所有方法做统一处理,即都返回null。
但是有的时候我们需要一些方法在服务不可用时告诉我们一些其他信息,以便做其他处理。如更新/删除等。此时,可以通过以下的方式。
在业务接口所在的包中,定义一个类,该类的命名需要满足以下规则:
配置mock=”true”的情况,对于上面的例子即在StudentService的同个路径下,添加类StudentServiceMock,实现如下:
public class StudentServiceMock implements StudentService {
public void doSomething1() {
throw new RuntimeException("fail!");
}
public String doSomething2(String str) {
return null;
}
}
修改消费者dubbo.xml
<dubbo:reference id="StudentService" interface="com.sun.service.StudentService" timeout="10000" check="false" mock="true">
参考资料:
https://dubbo.incubator.apache.org/zh/overview/what/overview/