Dubbo 01 基础概念与入门工程搭建

Dubbo 01 基础概念与入门工程搭建

1. 概述基本概念

定义

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:

  1. 面向接口的远程方法调用
  2. 智能容错和负载均衡
  3. 以及服务自动注册和发现。

架构

角色

  1. Registry 注册中心,用于服务的注册与发现。
  2. Provider 服务提供者,通过向 Registry 注册服务。
  3. Consumer 服务消费者,通过从 Registry 发现服务。后续直接调用 Provider ,无需经过 Registry 。
  4. Monitor 监控中心,统计服务的调用次数和调用时间。
  5. Container 服务运行容器。

调用关系

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2. 入门工程搭建

2.0 安装Zookeeper

以本机为例:官网下载包,安装后有如下环境:

  • 端口:2181
  • 安装地址:E:\apache-zookeeper-3.6.1\bin
  • 启动服务:E:\apache-zookeeper-3.6.1\bin\zkServer.cmd
  • 客户端: E:\apache-zookeeper-3.6.1\bin\zkCli.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 接口,提供给消费者使用。

  1. UserDTO

nb\yucai\dubbo\nacosdemo\dto下,新建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;
    }
}
  1. UserRpcService

nb\yucai\dubbo\nacosdemo新建UserRpcService.java

public interface UserRpcService {
    /**
     * 根据指定用户编号,获得用户信息
     *
     * @param id 用户编号
     * @return 用户信息
     */
    UserDTO get(Integer id);

    Integer add(UserDTO dto);
}

2.1.2 Provide

  1. 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>
  1. 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的参数

  1. 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);
    }
}

  1. 新建Dubbo.xml的配置文件:src\main\resources\dubbo.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>
  1. 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

  1. 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>
  1. 配置文件
    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
  1. 配置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>
  1. 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

  1. 引入依赖

基本与XML方式实现一致,可参考上文

  1. 应用配置文件
    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文件进行配置

  1. 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 - 女
    }
}
  1. ProviderApplication

正常建立即可,无需添加@ImportResource注解,引入dubbo.xml即可

Consumer

  1. 引入依赖

基本与XML方式实现一致,可参考上文

  1. 应用配置文件

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
  1. 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 的整合,贼方便。

  1. Nacos官网下载,运行即可。

  2. API

以上文注解式配置的方法为例,仍采用上述Service,无需改动

  1. 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
  1. Consumer

整合过程与上述Provider完全一致。

  1. 验证

登录Nacos控制台即可看见。

整合Sentinel

Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。

次小节进行 Dubbo 和 Sentinel 的整合,使用 Sentinel 进行 Dubbo 的流量保护。Sentinel已经对 Dubbo 进行适配,所以我们只要引入它,基本就完成了 Dubbo 和 Sentinel 的整合,贼方便。

  1. Api

与注解配置的Api一致,无需改动

  1. 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);
    }
}
  1. 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. 下篇预告

  1. 添加参数验证
  2. 自定义实现拓展点
posted @ 2020-09-17 20:39  AaronPi  阅读(152)  评论(1编辑  收藏  举报