Dubbo快速实践
文章目录
- 架构相关概念
- 集群和分布式
- 架构演进
- Dubbo概述
- Dubbo快速入门
- 前置准备
- 配置服务接口
- 配置Provider
- 配置Consumer
- Dubbo基本使用总结
本文参考https://www.bilibili.com/video/BV1VE411q7dX
架构相关概念
集群和分布式
- 集群:很多“人”一起 ,干一样的事。
- 一个业务模块,部署在多台服务器上。
- 一个业务模块,部署在多台服务器上。
- 分布式:很多“人”一起,干不一样的事。这些不一样的事,合起来是一件大事。
- 一个大的业务系统,拆分为小的业务模块,分别部署在不同的机器上。
- 一个大的业务系统,拆分为小的业务模块,分别部署在不同的机器上。
- 集群和分布式两者一般结合使用
架构演进
单体架构
优点:
- 简单:开发部署都很方便,小型项目首选
缺点:
- 项目启动慢
- 可靠性差
- 可伸缩性差
- 扩展性和可维护性差
- 性能低
垂直结构
垂直架构是指将单体架构中的多个模块拆分为多个独立的项目。形成多个独立的单体架构。
注意:
- 这多个独立的项目之间是不会进行通信的,这也就会出现重复功能的问题。比如app1和app2中都需要用户信息,那么就可能都要写用户模块(E),这就会非常的冗余
垂直架构存在的问题:
- 重复功能太多
分布式架构
分布式架构是指在垂直架构的基础上,将公共业务模块抽取出来,作为独立的服务,供其他调用者消费,以实现服务的共享和重用。
那么如何去调用这个服务的提供者呢?就要通过RPC
RPC: Remote Procedure Call 远程过程调用。有非常多的协议和技术来都实现了RPC的过程。比如:HTTP REST风格,Java RMI规范、WebService SOAP协议、Hession等等。
分布式架构存在的问题:
- 服务提供方一旦产生变更,所有消费方都需要变更。
- 例如:
SOA架构
在分布式架构中我们是在不同项目之间直接进行调用,所以造成一方变更,多方也要跟着变的情况,所以在SOA架构中,服务之间就不直接进行调用,而是加一个中介,把调用的需求给他,让它去给我们进行调用。我们只需要在中介中去维护调用关系即可,而不必像原来一样。
SOA:(Service-Oriented Architecture,面向服务的架构)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。
ESB:(Enterparise Servce Bus) 企业服务总线,服务中介。主要是提供了一个服务于服务之间的交互。ESB 包含的功能如:负载均衡,流量控制,加密处理,服务的监控,异常处理,监控告急等等。
微服务架构
微服务架构是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。
微服务架构 = 80%的SOA服务架构思想 + 100%的组件化架构思想 + 80%的领域建模思想
特点:
- 服务实现组件化:开发者可以自由选择开发技术。也不需要协调其他团队
- 服务之间交互一般使用REST API
- 去中心化:每个微服务有自己私有的数据库持久化业务数据
- 自动化部署:把应用拆分成为一个一个独立的单个服务,方便自动化部署、测试、运维
注意:Dubbo 是 SOA时代的产物,SpringCloud 是微服务时代的产物
Dubbo概述
- Dubbo是阿里巴巴公司开源的一个高性能、轻量级的 Java RPC 框架。
- 致力于提供高性能和透明化的
RPC 远程服务调用方案
,以及SOA 服务治理方案
。 - 官网:http://dubbo.apache.org
架构:
Dubbo官方推荐使用Zookeeper作为注册中心
zookeeper的安装可以参考这篇文章:
windows安装Zookeeper
Dubbo快速入门
使用Dubbo的方式有如下三种:
- 基于 Dubbo API
- 基于Spring Boot Starter
- 基于Spring XML
这里我们使用Starter的方式进行快速入门:
参考文档:Dubbo 基于 Spring Boot Starter 开发微服务应用
前置准备
- 安装Zookeeper,并启动
- 构建一个Dubbo的小demo
- 这一步骤可以参考上后面的文档
配置服务接口
也就是配置interface子项目
服务接口是 Dubbo 中沟通消费端和服务端的桥梁。我们一般把他单独放在一个项目中。
我们在这个项目中随意定义一个接口:
public interface DemoService {
String sayHello(String name);
}
在 DemoService 中,定义了 sayHello 这个方法。后续服务端发布的服务,消费端订阅的服务都是围绕着 DemoService 接口展开的。
配置Provider
配置文件:
dubbo:
application:
name: dubbo-demo-provider
protocol:
name: dubbo
port: -1
registry:
address: zookeeper://localhost:2181 # 替换成自己的注册中心地址
在这个配置文件中,定义了 Dubbo 的应用名、Dubbo 协议信息、Dubbo 使用的注册中心地址。
定义了服务接口之后,可以在服务端这一侧定义对应的实现,这部分的实现相对于消费端来说是远端的实现,本地没有相关的信息。
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
在 DemoServiceImpl 中,实现了 DemoService 接口,对于 sayHello 方法返回 Hello name。
注:在DemoServiceImpl 类中添加了 @DubboService
注解,通过这个配置可以基于 Spring Boot 去发布 Dubbo 服务。
然后我们写一个启动类:
@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
最后我们启动Provider。
配置Consumer
配置文件和前面一样:
dubbo:
application:
name: dubbo-demo-provider
protocol:
name: dubbo
port: -1
registry:
address: zookeeper://localhost:2181 # 替换成自己的注册中心地址
接下来我们在消费端去远程调用这个接口:
@Component
public class Task implements CommandLineRunner {
@DubboReference
private DemoService demoService;
@Override
public void run(String... args) throws Exception {
String result = demoService.sayHello("world");
System.out.println("Receive result ======> " + result);
new Thread(()-> {
while (true) {
try {
Thread.sleep(1000);
System.out.println(new Date() + " Receive result ======> " + demoService.sayHello("十八岁讨厌编程"));
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}).start();
}
}
在 Task 类中,通过@DubboReference
从 Dubbo 获取了一个 RPC 订阅,这个 demoService 可以像本地调用一样直接调用。在 run方法中创建了一个线程进行调用。
最后我们写一个启动类,然后启动:
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
通过命令行我们可以看到远程调用是成功了的:
Dubbo基本使用总结
配置文件
消费者、服务者都要配置:
dubbo:
application:
name: dubbo-demo-provider #服务名,随便取
protocol:
name: dubbo
port: -1
registry:
address: zookeeper://localhost:2181 #注册中心的地址
注意:
dubbo的protocol下面的name和port是用来配置通信协议和端口的。name是指定通信协议的名称,例如dubbo, rmi, http, hessian等。port是指定通信协议的端口号,例如dubbo的默认端口是20880,rmi的默认端口是1099,http和hessian的默认端口是80。如果port不填或者等于-1,那么会自动分配一个未使用的端口。为了保证端口的范围可控,从Dubbo 2.4.0+开始,端口会根据对应协议的默认端口递增。
三个注解
- @DubboService:定义好 Dubbo 服务接口后,提供服务接口的实现逻辑,并用 @DubboService 注解标记,就可以实现 Dubbo 的服务暴露
- @DubboReference:自动注入为 Dubbo 服务代理实例
- @EnableDubbo:必须配置,否则将无法加载 Dubbo 注解定义的服务,@EnableDubbo 一般定义在启动类上
可以使用 Java Config 代替注解
注意,Java Config 是 DubboService 或 DubboReference 的替代方式,对于有复杂配置需求的服务建议使用这种方式。
@Configuration
public class ProviderConfiguration {
@Bean
public ServiceConfig demoService() {
ServiceConfig service = new ServiceConfig();
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
service.setGroup("dev");
service.setVersion("1.0.0");
Map<String, String> parameters = new HashMap<>();
service.setParameters(parameters);
return service;
}
}