1、概述
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。Dubbo一开始是由Alibaba公司开发的高性能、轻量级的Java RPC框架,专注于服务之间的调用,后来Alibaba将此项目捐献给Apache基金会,Apache将Dubbo设置为其名下的顶级项目。而如今由于云原生生态和微服务概念的火爆,Dubbo官方快速在此环境定位自己的位置,放开自己的视野,开拓格局,不单单在服务调用上发展,逐渐在服务治理、服务监控、服务网关上发力,Dubbo的生态圈日趋完善。如今Dubbo3.x更是被官方定义为面向云原生的下一代 RPC 服务框架。Dubbo3基于Dubbo2.x 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。
2、RPC
想要对Dubbo进行一个大概的了解,首先要对RPC进行一个简单的认识。在日常中,能清楚的感受到很多人没有对此方面进行一个深入了解,觉得RPC就是一种协议类似的想法,这是不正确的,RPC和HTTP这种协议不是一个层级上的。RPC全称为Remote Procedure Call,意思是远程过程调用,这是一种技术上的概念名词。HTTP是一种协议,RPC可以通过HTTP远程调用程序来实现。也可以通过Socket自己去实现一套协议来实现。此处就拿Dubbo而言,它定义好了自己的RPC通信协议与编程方式。RPC是一种概念,它实现了能像调用本地方法一样调用远程方法的功能、轻量且没有多余信息、便于管理、长链接减少网络开销、更安全等。
与远程过程调用相对的来讲则是本地过程调用,本地方法调用是在进程内进行的方法调用,我们可以这么理解,我们运行的程序中类与类之间的方法的相互调用。而远程过程调用,则是指两个及以上多个进程间的方法相互调用,调用方式基本是通过进行网络传输数据来实现。可以举个例子,A进程(服务)要调用B进程(服务)的一个方法的时候,需要通过网络将要调用的类、方法名、参数、参数类型、版本、组等信息传输给B进程(服务),B进程(服务)执行完后将执行结果再通过网络传输给回A进程(服务)。当然,在两个进程间上述提到所需的信息在两个类中需要保持一致才能被成功的调用。有一点要注意的是Dubbo的服务间调用时,所传输的数据都必须经过序列化。
左边的是本地过程调用,右边则是远程过程调用
3、Dubbo的基本架构
该图是Dubbo官方提供的简单架构,对这些节点角色进行一个简要的介绍:
- Provider:暴露服务的服务提供方
- Container:服务运行容器
- Consumer:调用远程服务的服务消费方
- Registry:服务注册与发现的注册中心
- Monitor:统计服务的调用次数和调用时间的监控中心
再来点八股文内容:
- 服务容器Container负责启动,加载,运行服务提供者。
- 服务提供者Provider在启动时,向注册中心注册自己所能提供的服务。
- 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务并将将提供者元信息通知给 Consumer。
- 注册中心Registry返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者Consumer和提供者Provider,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心Monitor。
一些小tips:
- 注册中心和监控中心是可选的,你可以不要监控,也可以不要注册中心,直接在配置文件里面写然后提供方和消费方直连。
- 注册中心、提供方和消费方之间都是长连接,和监控方不是长连接,并且消费方是直接调用提供方,不经过注册中心。
- 就算注册中心和监控中心宕机了也不会影响到已经正常运行的提供者和消费者,因为消费者有本地缓存提供者的信息。
4、Dubbo基本使用
4.1、基于注解远程调用
首先我们创建三个模块,这三个模块分别对应接口api,消费者,生产者。此处我的Dubbo示例版本为Dubbo3.1.3,使用Nacos2.1.2协调服务发现
4.1.1、dubbo-api
该模块为公共模块,作用是提供消费者、生产者所需依赖和存放需要进行远程调用的接口,便于统一管理,类似本地调用,该模块不需要引入太多依赖。在模块中创建DemoService接口如下所示
public interface DemoService {
String sayHello(String message);
}
我们后续的远程调用将围绕该接口进行,实现简单的远程调用展示。
4.1.2、dubbo-annotation-provider
该模块的作用是将相关服务注册至注册中心,供消费者订阅使用。在pom文件中引入如下依赖即可立即使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mieah</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.1.3</version>
</dependency>
我们还需要在application.yaml中对dubbo的进行一些配置,对服务进行命名、配置注册中心所在地址和对包进行一个扫描
dubbo:
application:
name: annotation-provider
registry:
address: nacos://localhost:8848
scan:
base-packages: com.mieah
创建AnnotationDemoServiceImpl类来实现DemoService接口,并使用Dubbo给出@DubboService注解对该类进行一个声明,Dubbo会将该类进行一个自动注册
@DubboService
public class AnnotationDemoServiceImpl implements DemoService{
@Override
public String sayHello(String message) {
return "Hello Dubbo!" + message;
}
}
进行如上前置操作后,启动程序,在nacos控制台可以看见服务的注册
4.1.3、dubbo-annotation-consumer
该模块的作用是从注册中心拉取服务列表,供消费者订阅使用。在pom文件中引入如下依赖即可立即使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mieah</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.1.3</version>
</dependency>
我们还需要在application.yaml中对dubbo的进行一些配置,对服务进行命名、配置注册中心所在地址和对包进行一个扫描
dubbo:
application:
name: annotation-consumer
registry:
address: nacos://localhost:8848
scan:
base-packages: com.mieah
我们通过创建一个ConsumerFacede类来进行一个远程服务的调用展示,通过Dubbo给出@DubboReference对注册的服务进行一个拉取并依赖注入
@Component
public class ConsumerFacede {
@DubboReference
private DemoService demoService;
public void annotationDemo(String message) {
System.out.println(demoService.sayHello(message));
}
}
在应用程序入口的main方法中进行ConsumerFacede的获取,并调用demo方法,然后启动程序
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(ConsumerApplication.class, args);
ConsumerFacede consumerFacede = applicationContext.getBean(ConsumerFacede.class);
consumerFacede.annotationDemo("TopView!");
}
等一段时间后,我们可以在控制台看见如下输出,成功进行了服务间的远程调用
在Nacos控制台也可以看见多了一条订阅者信息
4.2、基于API远程调用
首先我们创建三个模块,这三个模块分别对应接口api,消费者,生产者。此处我的Dubbo示例版本为Dubbo3.1.3,使用Nacos2.1.2协调服务发现
4.2.1、dubbo-api
该模块为公共模块,作用是提供消费者、生产者所需依赖和存放需要进行远程调用的接口,便于统一管理,类似本地调用,该模块不需要引入太多依赖。在模块中创建DemoService接口如下所示
public interface DemoService {
String sayHello(String message);
}
我们后续的远程调用将围绕该接口进行,实现简单的远程调用展示。
4.2.2、dubbo-programming-provider
该模块的作用是将相关服务注册至注册中心,供消费者订阅使用。在pom文件中引入如下依赖即可立即使用
<dependencies>
<dependency>
<groupId>com.mieah</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
和前面基于注解一样,我们在这里同样要实现DemoService接口,如下创建ProgrammingDemoService,可以注意到的是,我们这边没有用@DubboService注解
public class ProgrammingDemoService implements DemoService{
@Override
public String sayHello(String message) {
return "Hello Dubbo!" + message;
}
}
创建一个ProviderDemo类通过api进行手动的注册服务,配置ServiceConfig接口及其实现类,然后通过DubboBootstrap进行相应的注册
public class ProviderDemo {
public static void main(String[] args) {
ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(DemoService.class);
serviceConfig.setRef(new ProgrammingDemoService());
DubboBootstrap.getInstance()
.application("programming-provider")
.registry(new RegistryConfig("nacos://localhost:8848"))
.service(serviceConfig)
.start()
.await();
}
}
运行程序,可以在Nacos控制台看见服务已经被注册
4.2.3、dubbo-programming-consumer
该模块的作用是从注册中心拉取服务列表,供消费者订阅使用。在pom文件中引入如下依赖即可立即使用
<dependencies>
<dependency>
<groupId>com.mieah</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
创建ConsumerDemo类来实现通过api手动订阅获取到注册中心中的实现类,配置ReferenceConfig的接口,通过DubboBootstrap指定注册中心地址并获取实例,调用其中方法运行程序
public class ConsumerDemo {
public static void main(String[] args) {
ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();
referenceConfig.setInterface(DemoService.class);
DubboBootstrap
.getInstance()
.application("programming-consumer")
.registry(new RegistryConfig("nacos://localhost:8848"))
.reference(referenceConfig);
DemoService demoService = referenceConfig.get();
System.out.println(demoService.sayHello("MieAh!"));
}
}
等一段时间后,我们可以在控制台看见如下输出,成功进行了服务间的远程调用
在Nacos控制台也可以看见多了一条订阅者信息
5、小结
从上述我们已经对Dubbo有了一个概要的了解,学会了怎么去通过分别使用注解和API实现服务间的远程调用,对Dubbo进行一个基本的使用。Dubbo这个框架的神奇之处也是非常可观的,相信上述操作的复现并不困难。接下来就是对Dubbo的SPI进行一个相应的深入。