1.介绍

  • Dubbo是阿里巴巴公司开源的一个高性能、轻量级的 Java RPC 框架。
  • 致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。
  • 官网:http://dubbo.apache.org

目前Dubbo在企业中有两种开发思路

  • 基于SOA思想
    • 将传统单一应用拆分为web(消费者)模块和service(提供者)模块,基于Dubbo通信
  • 辅助SpringCloud架构提升效率
    • Dubbo基于TCP(传输层)协议,效率更高。可以替换Feign,提升高并发压力
  • Dubbo的基本架构
    • 服务提供者在启动时,向注册中心注册自己提供的服务。
    • 服务消费者在启动时,向注册中心订阅自己所需的服务。
    • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    • 服务消费者,从提供者地址列表中,基于负载均衡算法,选择提供者进行调用。
    • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

code

2.快速入门

  1. 下载nacos
  2. 下载DubboAdmin管理后台
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #1、下载代码: 
    git clone https://github.com/apache/dubbo-admin.git
    #2、在 dubbo-admin-server/src/main/resources/application.properties中指定注册中心地址
    #3、构建
    mvn clean package -D maven.test.skip=true
    #4、启动
    mvn --projects dubbo-admin-server spring-boot:run
    #或者
    cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar
    #5、访问 http://localhost:8080
  3. 搭建服务提供者
    1. 依赖导入
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      <dependencies>
      <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      </dependency>
      <!--mybatis-->
      <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      </dependency>

      <!--dubbo的起步依赖-->
      <dependency>
      <groupId>org.apache.dubbo</groupId>
      <artifactId>dubbo-spring-boot-starter</artifactId>
      <version>2.7.8</version>
      </dependency>

      <dependency>
      <groupId>org.apache.dubbo</groupId>
      <artifactId>dubbo-registry-nacos</artifactId>
      <version>2.7.8</version>
      </dependency>
      </dependencies>
    2. 将service,mapper,domain导入到提供者模块中
    3. 把实现类的@service注解改为@DubboService
    4. 配置application.yaml
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      server:
      port: 18081
      spring:
      datasource:
      url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      application:
      name: user-provider
      logging:
      level:
      cn.itcast: debug
      pattern:
      dateformat: HH:mm:ss:SSS
      #配置Dubbo提供者
      #Dubbo协议和访问端口
      dubbo:
      protocol:
      name: dubbo
      port: 20881
      #注册中心地址
      registry:
      address: nacos://127.0.0.1:8848
      #Dubbo注解的扫描
      scan:
      base-packages: cn.itcast.user.service
      code
  4. 搭建消费者
    1. 导入依赖
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      <dependencies>
      <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      </dependency>


      <!--dubbo的起步依赖-->
      <dependency>
      <groupId>org.apache.dubbo</groupId>
      <artifactId>dubbo-spring-boot-starter</artifactId>
      <version>2.7.8</version>
      </dependency>

      <dependency>
      <groupId>org.apache.dubbo</groupId>
      <artifactId>dubbo-registry-nacos</artifactId>
      <version>2.7.8</version>
      </dependency>
      </dependencies>
    2. 将controller,service接口导入到提供者模块中
    3. 把控制层的@Autowired注解改为@DubboReference
    4. 配置application.yaml
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      server:
      port: 18080
      spring:
      application:
      name: user-consumer
      logging:
      level:
      cn.itcast: debug
      pattern:
      dateformat: HH:mm:ss:SSS
      dubbo:
      registry:
      address: nacos://127.0.0.1:8848
      code
  5. 最佳实践
  • 将API接口抽取为独立模块,并且把接口有关的domain都放到这个模块中
    1. 抽取服务提供者的domain和service接口
    2. 在消费者和服务者中引入公共api依赖
    3. 在实体类实现Serializable反序列化

3.高级特性

3.1启动检查

  • 为了保障服务的正常可用,Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常
    • 当启动消费者时,会去检查服务站是否存在,如果不存在,则会报错
    • 关闭启动检查
      1
      2
      3
      4
      5
      dubbo:
      registry:
      address: nacos://127.0.0.1:8848
      consumer:
      check: false
    • 这时启动就不会报错,但是调用接口还是会报错

3.2多版本

  • 在正式系统中,为了保证系统可用性和更好的并发性,往往通过集群部署。
    • 如果提供者代码出现重大更新。如何对提供者升级部署呢?
      • Dubbo提供了提供者多版本的支持,平滑处理项目功能升级部署
      • 先升级一个服务者和一个消费者,等测试没问题在升级剩余的
    • 实现
      1. 编写新的UserServce实现类,作为新版本代码
      2. 在暴露服务时,指定服务版本
        • @DubboService(version = “2.0.0”)
      3. 消费者引用服务时,指定引用的服务版本
        • @DubboReference(version = “2.0.0”)

3.3超时与重试

  • 服务消费者在调用服务提供者发生了阻塞、等待的情形的时候,这个时候,服务消费者会一直等待下去。在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩
    • dubbo 利用超时机制来解决这个问题(使用timeout属性配置超时时间,默认值1000,单位毫秒)
    • 若超时时间较短,当网络波动时请求就会失败,Dubbo通过重试机制避免此类问题的发生
  • 消费者向提供者总共请求3次,所以重试机制对增删改等数据库操作可能造成问题,尽量只在查数据时使用
  • 配置重试机制
    • @DubboService(version = “2.0.0”,reties = 0)
      1
      2
      3
      4
      5
      6
      dubbo:
      registry:
      address: nacos://127.0.0.1:8848
      consumer:
      check: false
      reties: 0

3.4负载均衡

  • 在集群部署时,Dubbo提供了4种负载均衡策略,帮助消费者找到最优提供者并调用
    • Random :按权重随机,默认值。按权重设置随机概率。
    • RoundRobin :按权重轮询
    • LeastActive:最少活跃调用数,相同活跃数的随机。
    • ConsistentHash:一致性 Hash,相同参数的请求总是发到同一提供者。
  • 使用
    @DubboReference(loadbalance = “roundrobin”)

4.Spring-cloud整合Dubbo

4.1为什么需要Dubbo

  • Feign基于Http协议(应用层),在高并发场景下性能不够理想,容易成为性能瓶颈
  • Dubbo框架的通信协议采用TCP协议(数据传输层)
  • Dubbo默认通过Netty构造TCP长连接的方式进行通信,性能较高
  • 使用SpringCloud整合Dubbo,即为强强联合。
  • 官方地址: https://github.com/alibaba/spring-cloud-alibaba
    code
    code

4.2案例

code
code
code

  • 抽取接口模块dubbo-api
    • 导入依赖
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>2.2.5.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
      </dependency>

      <!--nacos注册中心的依赖-->
      <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
      </dependency>

      <!--springcloud alibaba dubbo依赖 -->
      <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-dubbo</artifactId>
      </dependency>

      <dependency>
      <groupId>cn.itcast</groupId>
      <artifactId>dubbo-api</artifactId>
      <version>1.0-SNAPSHOT</version>
      </dependency>

    • 抽取接口
      1
      2
      3
      4
      5
      package cn.itcast.dubbo.api;
      import cn.itcast.dubbo.domain.User;
      public interface UserService {
      User queryById(Long id);
      }
  • 改造服务提供者
    • 暴露接口
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @DubboService
      public class UserServiceImpl implements UserService {

      @Autowired
      private UserMapper userMapper;

      public User queryById(Long id) {
      return userMapper.findById(id);
      }
      }
    • 配置yaml文件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
        spring:
      datasource:
      url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      application:
      name: user-service
      cloud:
      nacos:
      discovery:
      server-addr: localhost:8848
      #配置dubbo,注册中心,暴露的端口和协议,dubbo注解的包扫描
      dubbo:
      protocol:
      name: dubbo
      port: 20881
      registry:
      address: spring-cloud://localhost #使用SpringCloud中的注册中心
      scan:
      base-packages: cn.itcast.user.service #dubbo中包扫描
  • 改造服务消费者
    • 引入dubbo服务
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      @RestController
      @RequestMapping("order")
      public class OrderController {

      @Autowired
      private OrderService orderService;

      @DubboReference
      private UserService userService;

      @GetMapping("{orderId}")
      public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
      //根据id查询订单
      Order order = orderService.queryOrderById(orderId);
      //获取用户id
      Long userId = order.getUserId();
      //查询用户
      User user = userService.queryById(userId);
      //设置用户对象
      order.setUser(user);
      // 根据id查询订单并返回
      return order;
      }
      }
    • 配置yaml文件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
        spring:
      application:
      name: order-service
      cloud:
      nacos:
      discovery:
      server-addr: localhost:8848
      #dubbo配置
      dubbo:
      registry:
      address: spring-cloud://localhost #使用cloud的注册中心
      consumer:
      check: false #dubbo默认有启动检查
      retries: 0 #dubbo内置的重试机制