Dubbo 技术简介

Apache Dubbo 是一个高可用的,基于 Java 的开源 RPC 框架。Dubbo 不仅具备 RPC 访问功能,还包含服务治理功能。

发展历程

  1. Dubbo 最开始是阿里巴巴内部使用的 RPC 框架
  2. 2011 年对外提供,随后断断续续地更新
  3. 2019 年捐献给 Apache,由 Apache 继续维护以后的版本

Dubbo 建构(重要)

dubbo-architecture

关系

  • init:创建
  • async:异步
  • sync:同步

角色

  • Provider:提供者,编写持久层和事务代码
  • Container:容器(Spring 容器),Dubbo 完全是基于 Spring 实现的
  • Registry:注册中心,放置所有 Provider 对外提供的信息,包含 Provider 的 IP、访问端口、访问遵守的协议、对外提供的接口、接口中有那些方法等相关信息。
  • Consumer:消费者(RPC 调用者,SOA 调用服务的项目),开发中也是一个项目,编写 service 和 controller,调用 XXXXServiceImpl 中的方法。
  • Monitor:监控中心,监控 Provider 的压力情况等,每隔两分钟 Consumer 和 Provider 会把调用次数发送给 Monitor。

Dubbo 支持的协议

Dubbo 协议(官方推荐)

  • 使用 NIO 复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)。
  • 大文件上传时,可能会出现问题(不使用 Dubbo 进行文件上传)。

RMI 协议

  • JDK 自带的能力
  • 偶尔连接失败

Hessian 协议

  • 可与原生 Hessian 互操作,基于 HTTP 协议
  • 需要 hessian.jar 支持,http 短连接性能开销大

Dubbo 支持的注册中心

zookeeper(官方推荐)

  • 支持分布式、周边生态好
  • 受限于 zookeeper 软件的稳定性,尽管其稳定性较优

Multicast

  • 去中心化、不需要单独安装软件
  • Provider 和 Consumer 和 Registry 不能跨路由(无法在公网使用)

Redis(优秀)

  • 支持集群、性能高
  • 要求服务器时间同步,否则可能出现集群失败

Simple

  • 标准的 RPC 服务,没有兼容问题
  • 不支持集群

第一个 Dubbo 项目

  1. 创建一个父工程:DubboParent

  2. 配置父工程依赖(注意 Dubbo 和 zookeeper 的版本兼容):

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.11</version>
        </parent>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                    <version>2.7.11</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                    <version>2.7.11</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo-spring-boot-starter</artifactId>
                    <version>3.0.5</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.curator</groupId>
                    <artifactId>curator-recipes</artifactId>
                    <version>5.2.0</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.curator</groupId>
                    <artifactId>curator-x-discovery</artifactId>
                    <version>5.2.0</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
  3. 创建 api 模块:

    api 模块中的接口类,往往以 XXDubboService 来命名。

    public interface DemoDubboService {
    
        public String demo(String param);
    }
    
  4. 创建 provider 模块:

    provider 模块中的类,实现了 api 模块中的接口,调用了数据库,并将服务注册到 zookeeper(或其他注册中心)。

    @DubboService
    public class DemoDubboServiceImpl implements DemoDubboService {
    
        @Override
        public String demo(String param) {
            System.out.println("DEMO 执行中...");
            return param + "ABC";
        }
    }
    
    @SpringBootApplication
    @EnableDubbo
    public class ProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }
    
    dubbo:
      application:
        name: dubbo-provider
      registry:
        address: zookeeper://192.168.80.130:2181
      protocol:
        port: 20884
    

    在使用 Dubbo 编程时,Provider 的 Service 注解使用 @DubboService(老版本使用 dubbo 包中的 Service 注解),并且在启动类中加上 @EnableDubbo

  5. 创建 consumer 模块:

    consumer 模块也需要导入 api 模块,以使用其中的接口类。配置好 dubbo 的信息,并且设置 EnableDubbo,可以通过 @DubboReference 直接将 api 模块的实现类注入。

    public interface DemoService {
    
        public String demo();
    }
    
    @Service
    public class DemoServiceImpl implements DemoService {
    
        @DubboReference		// 这里使用 DubboReference 表明这应该从 Provider 中获取
        DemoDubboService demoDubboService;
    
        @Override
        public String demo() {
            return demoDubboService.demo("有马加奈");
        }
    }
    
    @Controller
    public class DemoController {
    
        @Autowired
        private DemoService demoService;
    
        @ResponseBody
        @RequestMapping("/demo")
        public String demo() {
    
            return demoService.demo();
        }
    }
    
    @SpringBootApplication
    @EnableDubbo
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
    dubbo:
      application:
        name: dubbo-consumer
      registry:
        address: zookeeper://192.168.80.130:2181
    
  6. 依次启动:zookeeper、provider 启动类、consumer 启动类,完成 consumer 对 provider 的调用。

负载均衡

  • 集群:一个内容,部署多次,形成的整体成为集群。集群的每个个体都部署到不同的服务器上。
  • 伪集群:集群中的内容部署到同一台服务器上,通过不同的端口区分个体。

负载均衡就是在使用集群的前提下,当访问整个集群时,分配集群中的每个结点被访问次数或频率的策略。

Dubbo 内置策略

Random:随机

随机访问集群中的结点,访问概率和权重有关。

RoundRobin:轮询

按照一定的顺序进行轮询,访问频率和权重有关。

LeastActive:最少活跃

活跃数相同的随机选择,活跃数较小的优先访问(总是分配给收到「最闲」的结点)。

ConsistentHash:一致性哈希

相同的请求参数会被发送到一个 provider。

使用 Dubbo 设置负载均衡

@DubboReference

  • 可以配置负载均衡策略 loadbalance:
@DubboReference(loadbalance = "roundrobin")
DemoDubboService demoDubboService;

@DubboService

  • 可以配置负载均衡策略 loadbalance。
  • 可以配置(负载均衡策略的)权重 weight。
@DubboService(loadbalance = "roundrobin", weight = 4)
public class DemoDubboServiceImpl implements DemoDubboService {

配置文件中配置

全局配置所有 provider 和 consumer 的负载均衡效果。

dubbo:
  application:
    name: dubbo-provider
  registry:
    address: zookeeper://192.168.80.130:2181
  protocol:
    port: 20884
  provider:
    loadbalance: random
  consumer:
    loadbalance: random