Dubbo 01 基础概念与入门工程搭建
1. 概述基本概念
定义
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 以及服务自动注册和发现。
架构
角色
- Registry 注册中心,用于服务的注册与发现。
- Provider 服务提供者,通过向 Registry 注册服务。
- Consumer 服务消费者,通过从 Registry 发现服务。后续直接调用 Provider ,无需经过 Registry 。
- Monitor 监控中心,统计服务的调用次数和调用时间。
- Container 服务运行容器。
调用关系
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
2. 入门工程搭建
2.0 安装Zookeeper
以本机为例:官网下载包,安装后有如下环境:
- 端口:2181
- 安装地址:E:apache-zookeeper-3.6.1in
- 启动服务:E:apache-zookeeper-3.6.1inzkServer.cmd
- 客户端: E:apache-zookeeper-3.6.1inzkCli.cmd
2.1 XML方式
dubbo-xml-demo
├─user-rpc-service-api
├─user-rpc-service-consumer
└─user-rpc-service-provider
2.1.1 Api
user-rpc-service-api 项目,服务接口,定义 Dubbo Service API 接口,提供给消费者使用。
- UserDTO
nbyucaidubbo acosdemodto下,新建UserDTO模拟传输对象
@Data
public class UserDTO implements Serializable {
/**
* 用户编号
*/
private Integer id;
/**
* 昵称
*/
private String name;
/**
* 性别
*/
private Integer gender;
public UserDTO setName(String name) {
this.name = name;
return this;
}
public UserDTO setId(Integer id) {
this.id = id;
return this;
}
public UserDTO setGender(Integer gender) {
this.gender = gender;
return this;
}
}
- UserRpcService
nbyucaidubbo acosdemo新建UserRpcService.java
public interface UserRpcService {
/**
* 根据指定用户编号,获得用户信息
*
* @param id 用户编号
* @return 用户信息
*/
UserDTO get(Integer id);
Integer add(UserDTO dto);
}
2.1.2 Provide
- pom.xml添加如下依赖
<!-- 引入定义的 Dubbo API 接口 -->
<dependency>
<groupId>nb.yucai</groupId>
<artifactId>user-rpc-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 引入 Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 实现对 Dubbo 的自动化配置 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.4.1</version>
</dependency>
<!-- 使用 Zookeeper 作为注册中心 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
- application.yml中添加dubbo配置
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-provider # 应用名
# Dubbo 注册中心配
registry:
address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 服务提供者协议配置
protocol:
port: -1 # 协议端口。使用 -1 表示随机端口。
name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档
# Dubbo 服务提供者配置
provider:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
filter: -exception # 去掉 ExceptionFilter
UserRpcService:
version: 1.0.0
# validation: true 开启将验证所有Service的参数
- UserRpcServiceImpl
在nb.yucai.dubbo.nacosdemo.service包下创建UserRpcService的实现类
@Service
public class UserRpcServiceImpl implements UserRpcService {
@Override
public UserDTO get(Integer id) {
return new UserDTO().setId(id)
.setName("没有昵称:" + id)
.setGender(id % 2 + 1); // 1 - 男;2 - 女
}
@Override
public Integer add(UserDTO dto) {
if("yucai".equals(dto.getName())){
throw new ServiceException(ServiceExceptionEnum.USER_EXISTS);
}
return Math.toIntExact(System.currentTimeMillis() / 1000);
}
}
- 新建Dubbo.xml的配置文件:srcmain esourcesdubbo.xml
<dubbo:service/>
可以注册为Dubbo服务的提供者
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务提供者暴露服务配置 -->
<dubbo:service ref="userRpcServiceImpl" interface="nb.yucai.dubbo.nacosdemo.UserRpcService"
version="${dubbo.provider.UserRpcService.version}" validation="true" />
</beans>
- ProviderApplication
ProviderApplication类启动项目,提供Dubbo服务
@SpringBootApplication
@ImportResource("classpath:dubbo.xml") //读取Dubbo配置文件
public class ProviderApplication {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(ProviderApplication.class, args);
}
}
此时链接Zookeeper,输入命令ls /dubbo
可以看到服务UserRpcService即为成功
2.1.3 Consumer
- pom.xml引入依赖
<!-- 引入定义的 Dubbo API 接口 -->
<dependency>
<groupId>nb.yucai</groupId>
<artifactId>user-rpc-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 引入 Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 实现对 Dubbo 的自动化配置 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.4.1</version>
</dependency>
<!-- 使用 Zookeeper 作为注册中心 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
- 配置文件
resource下创建application.yml文件,添加Dubbo相关的配置,如下所示
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-consumer # 应用名
# Dubbo 注册中心配置
registry:
address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 消费者配置
consumer:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
UserRpcService:
version: 1.0.0
- 配置XML文件,添加Dubbo的Service服务引用者
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 服务提供者暴露服务配置 -->
<dubbo:reference interface="nb.yucai.dubbo.nacosdemo.UserRpcService" id="userService"
version="${dubbo.consumer.UserRpcService.version}" validation="true"/>
</beans>
- ConsumerApplication
创建 ConsumerApplication 类,用于启动该项目,调用 Dubbo 服务。
- 在类上,添加 @ImportResource 注解,引入 dubbo.xml 配置文件。
- 在 UserRpcServiceTest 中,我们使用 @Resource 注解,引用通过 <dubbo:reference /> 配置的引用的 UserRpcService 服务对应的 UserRpcService Bean 。
@SpringBootApplication
@ImportResource("classpath:dubbo.xml")
public class ConsumerApplication {
public static void main(String[] args) {
// 启动 Spring Boot 应用
ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);
}
@Component
public class UserRpcServiceTest implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private UserRpcService userRpcService;
@Override
public void run(String... args) throws Exception {
UserDTO user = userRpcService.get(1);
logger.info("[run][发起一次 Dubbo RPC 请求,获得用户为({})]", user);
}
}
}|
注解方式
工程结构如下
dubbo-api-demo
├─user-apirpc-service-api
├─user-apirpc-service-consumer
└─user-apirpc-service-provider
Api
基本与XML方式实现一致,可参考上文
Provider
- 引入依赖
基本与XML方式实现一致,可参考上文
- 应用配置文件
application.yml中添加如下代码:
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-provider # 应用名
# Dubbo 注册中心配
registry:
address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 服务提供者协议配置
protocol:
port: -1 # 协议端口。使用 -1 表示随机端口。
name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档
# Dubbo 服务提供者配置
provider:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
filter: -exception # 去掉 ExceptionFilter
UserRpcService:
version: 1.0.0
scan:
base-packages: nb.yucai.dubbo.apidemo.service
多的是dubbo:scan:base-packages
配置, Dubbo将根据此配置查找Dubbo中定义的@Service
修饰的类,并将其暴露为Dubbo服务的提供者。因此,无需配置Dubbo的XML文件进行配置
- UserRpcServiceImpl
创建Dubbo的Service实现类:nb.yucai.dubbo.apidemo.service.UserRpcServiceImpl
import org.apache.dubbo.config.annotation.Service;
@Service(version = "${dubbo.provider.UserRpcService.version}")
public class UserRpcServiceImpl implements UserRpcService {
@Override
public UserDTO get(Integer id) {
return new UserDTO().setId(id)
.setName("没有昵称:" + id)
.setGender(id % 2 + 1); // 1 - 男;2 - 女
}
}
- ProviderApplication
正常建立即可,无需添加@ImportResource注解,引入dubbo.xml即可
Consumer
- 引入依赖
基本与XML方式实现一致,可参考上文
- 应用配置文件
application.yml中添加
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-consumer # 应用名
# Dubbo 注册中心配置
registry:
address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 消费者配置
consumer:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
UserRpcService:
version: 1.0.0
- ConsumerApplication
创建ConsumerApplication类
@SpringBootApplication
@Slf4j
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
@Component
public class UserRpcServiceTest implements CommandLineRunner {
@Reference(version = "${dubbo.consumer.UserRpcService.version}")
private UserRpcService userRpcService;
public void run(String... args) throws Exception {
UserDTO user = userRpcService.get(1);
log.info("[run][发起一次 Dubbo RPC 请求,获得用户为({})", user);
}
}
}
- 在类上,无需添加 @ImportResource 注解,引入 dubbo.xml 配置文件。
- 在 UserRpcServiceTest 中,我们使用 Dubbo 定义的
@Reference
注解,“直接”引用的 UserRpcService 服务对应的 UserRpcService Bean 。并且,在该注解里,我们可以添加该 Service 服务的配置。当然,每个属性和 <dubbo:reference /> 标签是基本一致的。
3. 整合开源组件
整合Nacos
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
本小节进行 Dubbo 和 Nacos 的整合,使用 Nacos 作为 Dubbo 的注册中心。
Dubbo 提供了 dubbo-registry-nacos 子项目,已经对 Nacos 进行适配,所以我们只要引入它,基本就完成了 Dubbo 和 Nacos 的整合,贼方便。
-
Nacos官网下载,运行即可。
-
API
以上文注解式配置的方法为例,仍采用上述Service,无需改动
- Provider
引入依赖
<!-- 使用 Zookeeper 作为注册中心 -->
<!--<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>-->
<!-- 使用 Nacos 作为注册中心 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.4.1</version>
</dependency>
application.yml中配置注册中心为Nacos:
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-provider # 应用名
# Dubbo 注册中心配
registry:
address: nacos://99.11.6.32:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 服务提供者协议配置
protocol:
port: -1 # 协议端口。使用 -1 表示随机端口。
name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档
# Dubbo 服务提供者配置
provider:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
filter: -exception # 去掉 ExceptionFilter
UserRpcService:
version: 1.0.0
# validation: true 开启将验证所有Service的参数
scan:
base-packages: nb.yucai.dubbo.nacosdemo.service
nacos:
config:
password: nacos
username: nacos
- Consumer
整合过程与上述Provider完全一致。
- 验证
登录Nacos控制台即可看见。
整合Sentinel
Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。
次小节进行 Dubbo 和 Sentinel 的整合,使用 Sentinel 进行 Dubbo 的流量保护。Sentinel已经对 Dubbo 进行适配,所以我们只要引入它,基本就完成了 Dubbo 和 Sentinel 的整合,贼方便。
- Api
与注解配置的Api一致,无需改动
- Provider
引入依赖
<!-- Sentinel 核心库 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.1</version>
</dependency>
<!-- Sentinel 接入控制台 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.7.1</version>
</dependency>
<!-- Sentinel 对 Dubbo 的支持 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.7.1</version>
</dependency>
新建sentinel.properties
csp.sentinel.dashboard.server=127.0.0.1:7070
创建UserController类,增加调用UserRpcService服务的HttpAPI接口
@RestController
@RequestMapping("/user")
public class UserController {
@Reference(version = "${dubbo.consumer.UserRpcService.version}")
private UserRpcService userRpcService;
@GetMapping("/get")
public UserDTO get(@RequestParam("id") Integer id) {
return userRpcService.get(id);
}
}
- Consumer
- 使用 ProviderApplication 启动服务提供者。使用 ConsumerApplication 启动服务消费者。
- 访问服务消费者的 http://127.0.0.1:8080/user/get?id=1 接口,保证相关资源的初始化。
下面,我们来演示使用 Sentinel 对服务消费者的流量控制。Sentinel 对服务提供者的流量控制是一样的,胖友可以自己去尝试。
- 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到看到 Dubbo 服务消费者产生的 nb.yucai.dubbo.apidemo.UserRpcService:get(java.lang.Integer) 资源。「新增流控规则」。填写流控规则,如下图所示: - 这里,我们创建的是比较简单的规则,仅允许该资源被每秒调用一次。
- 使用浏览器,快速访问 http://127.0.0.1:8080/user/get?id=1 接口两次,会调用 UserService#get(Integer id) 方法两次,会有一次被 Sentinel 流量控制而拒绝,返回结果如下图所示:
因为默认的错误提示不是很友好,所以胖友可以自定义 SpringMVC 全局错误处理器,对 Sentinel 的异常进行处理。
4. 下篇预告
- 添加参数验证
- 自定义实现拓展点