Dubbo基础入门

2020/02/03 Dubbo

Dubbo基础

Dubbo 是阿里巴巴开发的一个开源的高性能的RPC调用框架,是一个致力于提供高性能和透明化的RPC远程调用服务解决方案。

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

整体来说,一个公司业务系统的演进流程基本上都是从单体应用到多体应用。业务系统为单体应用时,不同业务模块的相互调用直接在本地JVM 进程内就可以完成;而变为多个应用时,相互之间进行通信的方式就不是简单地进行本地调用了,因为不同业务模块部署到了不同的JVM进程里,更常见的情况是部署到了不同的机器中,这时候,一个高效、稳定的RPC远程调用框架就变得非常重要。 本文主要内容

  • Dubbo的架构和各个组件之间的关系
  • Dubbo的各种调用

Dubbo架构

Dubbo的架构图如下,其中Dubbo构建的分布式系统架构中各个组件服务的作用以及相互关系:

  • Provider:为服务提供者集群,服务提供者负责暴露提供的服务,并将服务注册到服务注册中心。
  • Consumer:为服务消费者集群,服务消费者通过RPC远程调用服务提供者提供的服务。
  • Registry:负责服务注册与发现,提供目录服务。
  • Monitor:为监控中心,统计服务的调用次数和调用时间。并可以对服务设置权限、降级处理等,称为服务管控中心。

image

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

官网调用关系说明

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

以上各个组件的调用关系如下:

  • 服务提供方在启动时会将自己提供的服务注册到服务注册中心。
  • 服务消费方在启动时会去服务注册中心订阅自己需要的服务的地址列表,然后服务注册中心异步把消费方需要的服务接口的提供者的地址列表返回给服务消费方,服务消费方根据路由规则和设置的负载均衡算法选择一个服务提供者IP进行调用。
  • 监控平台主要用来统计服务的调用次数和调用耗时,即服务消费者和提供者在内存中累计调用服务的次数和耗时,并每分钟定时发送一次统计数据到监控中心,监控中心则使用数据绘制图表来显示。监控平台不是分布式系统必需的,但是这些数据有助于系统的运维和调优。服务提供者和消费者可以直接配置监控平台的地址,也可以通过服务注册中心获取。

简单的Dubbo服务实战

引入Dubbo的Maven依赖,代码如下:

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring.boot.version>2.7.6</spring.boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Web 相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.15</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot依赖管理 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

或者如下依赖

<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>dubbo</artifactId>
		<version>2.7.15</version>
	</dependency>

或者

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        
        <dependencyManagement>
           <!-- Apache Dubbo Dependencies -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencyManagement>

Dubbo代码详解

Demo使用Maven聚合功能构建,里面有三个模块

  • SDK模块是通用包,用来存放服务接口,这是为了代码复用,在服务提供者和消费者(泛化调用除外)的模块里需要引入这个包。
  • Provider模块为服务提供者相关模块,包含服务接口的实现类、服务提供方的同步处理请求、各种异步处理请求的实现等。
  • Consumer 模块为服务消费者相关模块,包含普通调用、各种异步调用、泛化调用、基于扩展接口实现的自定义负载均衡策略、集群容错策略等。

Dubbo SDK接口定义

HelloService接口如下:

public interface HelloService {
    String sayHello(String helloName);
}

同步发布与调用服务

服务提供端针对SDK中HelloService接口的实现类HelloServiceImpl的代码:

import com.dubbo.sdk.HelloService;

public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String helloName) {
        return "Hello World!" + helloName;
    }
}

服务提供端是如何发布服务的?

import com.dubbo.sdk.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.rpc.RpcContext;

import java.io.IOException;

public class SdkProvider {

    public static void main(String[] args) throws IOException {
        // 创建ServiceConfig实例
        ServiceConfig<HelloService> serviceConfig = new ServiceConfig<>();
        // 设置应用程序配置
        serviceConfig.setApplication(new ApplicationConfig("dubbo-provider"));
        // 设置注册中心
       RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181/");

        serviceConfig.setRegistry(registryConfig);
        // 设置接口和实现类
        // 设置服务分组和版本
        // dubbo中,服务接口+服务分组+服务版本 唯一的确定一个服务,同一个接口可以有不同版本,方便维护升级
        serviceConfig.setInterface(HelloService.class);
        serviceConfig.setRef(new HelloServiceImpl());
        serviceConfig.setVersion("1.0.0");
        serviceConfig.setGroup("dubbo-group");
//        RpcContext.getContext().setAttachment("name", "yangjingjing");

        // 导出服务,启动Netty监听链接请求,并将服务注册到注册中心
        serviceConfig.export();

        // 挂起线程,避免服务停止
        System.out.println("api provider service is started...");
        System.in.read();
    }
}

  • 创建了ServiceConfig实例,其泛型参数为HelloService接口;
  • 配置应用程序属性;
  • 设置服务注册中心地址,可知服务注册中心使用了ZooKeeper,并且ZooKeeper的地址为127.0.0.1,启动端口为2181,服务提供方会将服务注册到该中心。
  • 将接口与实现类设置到ServiceConfig实例;
  • 设置服务分组与版本,在Dubbo中,服务接口+服务分组+服务版本唯一地确定一个服务,同一个服务接口可以有不同的版本以便服务升级等,另外每个服务接口可以属于不同分组,所以当调用方消费服务时一定要设置正确的分组与版本。
  • 导出服务,启动NettyServer监听链接请求,并将服务注册到服务注册中心;代码8挂起线程,避免服务停止。

消费端消费处理

Consumer模块是如果同步调用服务的,SDKConsumer类的代码

import com.dubbo.sdk.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.RpcContext;

public class SdkConsumer {
    public static void main(String[] args) throws InterruptedException {
        // 创建服务引用对象实例
        ReferenceConfig<HelloService> referenceConfig = new ReferenceConfig<HelloService>();
        // 设置应用程序信息
        referenceConfig.setApplication(new ApplicationConfig("dubbo-consumer"));
        // 设置服务注册中心
        referenceConfig.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));

        //直连测试
        //referenceConfig.setUrl("dubbo://192.168.0.109:20880");

        // 设置服务接口和超时时间
        referenceConfig.setInterface(HelloService.class);
        referenceConfig.setTimeout(5000);

        // 设置自定义负载均衡策略与集群容错策略
        referenceConfig.setLoadbalance("myroundrobin");
        referenceConfig.setCluster("myCluster");

        // 设置服务分组与版本
        referenceConfig.setVersion("1.0.0");
        referenceConfig.setGroup("dubbo-group");

        // 引用服务
        HelloService greetingService = referenceConfig.get();

        // 设置隐式参数
        // 设置隐式参数,然后服务提供者就可以在服务实现类方法里获取参数值
        RpcContext.getContext().setAttachment("company", "alibaba");

        // 调用服务
        // 同步发起远程调用,然后当前线程会被阻塞直到服务提供方把结果返回
        System.out.println(greetingService.sayHello("world"));

        Thread.currentThread().join();
    }
}
  • 创建服务引用对象实例,其中泛型参数为GreetingService;
  • 创建应用程序配置对象
  • 设置服务注册中心地址,可知服务注册中心使用了ZooKeeper,并且ZooKeeper的地址为127.0.0.1,启动端口为2181,服务消费端启动后会从该中心获取服务提供者地址列表。
  • 设置服务接口和超时时间;
  • 设置自定义负载均衡策略与集群容错策略,后面会具体讲解;
  • 设置服务分组与版本,需要注意的是分组与版本要与服务提供者的分组与版本一致;
  • 引用服务;
  • 设置隐式参数,然后服务提供者就可以在服务实现类方法里获取参数值;代码17同步发起远程调用,然后当前线程会被阻塞直到服务提供方把结果返回。

服务消费端异步调用服务

Search

    微信好友

    博士的沙漏

    Table of Contents