Dubbo系列|一、Dubbo框架介绍

689 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

开篇

介绍主要介绍Dubbo框架、Dubbo的基本应用以及Dubbo的基本原理。

Dubbo介绍

官网:dubbo.apache.org/zh/index.ht…

Apache Dubbo 是一款微服务框架,为大规模微服务实践提供高性能 RPC 通信、流量治理、可观测性等解决方案,并提供了Java、Golang、Erlang、Rust等多种语言的SDK实现。

如果经常关注Dubbo的话可以注意到,官网对Dubbo的介绍经历了几个版本。

刚开始的时候是这么介绍的:

Apache Dubbo 是一款高性能、轻量级的开源 Java RPC 框架

经过了一段时间介绍更改为:

Apache Dubbo 是一款高性能、轻量级的开源 Java 服务 框架

可以看到对于Dubbo的定位已经发生了几次变化,从RPC框架->服务框架->微服务框架

Dubbo一开始把自己定位为一个RPC框架,专注于服务之间的调用。随着微服务的概念越来越火爆,Dubbo开始重新思考自己的定位,提升自己的格局,除了服务调用,开始逐渐向服务治理、服务监控、服务网关等方向扩展,随着Dubbo生态圈的逐渐完善,Dubbo慢慢的演变为一个成熟的微服务框架。

RPC

RPC是远程过程调用(Remote Procedure Call)的缩写形式,也就是我们常说的远程方法调用

与远程方法调用的是本地方法调用

本地方法调用指的是进程内部的方法调用,简单理解就是一个类中的方法调用本类或其他类的方法。

远程方法调用指的是两个进程内的方法相互调用,调用方式基本上都是通过网络传输数据来进行调用。例如,进程A的一个方法在调用进程B的一个方法时,通过网络把要调用的方法名参数类型参数版本等等信息传给进程B,进程B执行完后再通过网络把执行结果传递给进程A。

其中方法名参数类型参数版本这些信息,在两个进行之间传输需要达成一致才能进行调用。

Dubbo架构

image.png

Dubbo的总体架构图如上,图中各个节点的角色说明如下:

Container:服务运行的容器

Provider: 服务提供者

Registry:注册中心

Consumer:服务消费者

Monitor:监控中心

Registry

注册中心这个角色非常重要,他的职责主要为服务注册服务发现。Dubbo支持接口级别应用级别的服务发现和服务注册。

简单讲就是,我可以把自己的服务暴露在注册中心上,供其他服务来调用。或者我可以从注册中心上查找我可以调用哪些服务。

注册中心不是必选的,如果是本地直连的话是不需要部署注册中心的。

Dubbo支持的注册中心有:ZookeeperNacosRedisMulticast,其中ZookeeperNacos是最常用的注册中心。

Monitor

监控中心可以用来统计服务的调⽤次数和调⽤时间,这些统计数据会先在内存中汇总,然后发送到监控中心服务器。

另外监控中心可以为服务的运维监控提供数据。

监控中心支持自定义扩展,满足个性化运维需求。比如:服务健康检测、服务压力以及性能统计、服务告警等。

Monitor也不是必须的,监控中心宕机后也不会影响ProviderConsumer之间的服务调用。

Dubbo工作原理

Dubbo大致请求流程如下:

  1. 容器启动、加载、运行服务提供者。
  2. 服务提供者启动,提供自己的服务。提供服务的过程主要包括:提供服务的接口、注册服务(本地注册、注册中心注册)、暴露服务、启动Tomcat、Netty接受处理请求。把自己的主机地址、端口等信息注册到注册中心。
  3. 注册中心接受注册请求,保存服务名与服务器的地址映射关系,或感知服务地址变动通知消费者。
  4. 服务消费者启动时,从注册中心获取服务提供者的地址信息并缓存起来,根据负载均衡算法,从服务提供者地址列表里选择一个服务进行服务调用。
  5. 服务提供者和消费者在产生调用时,在内存中统计调用次数和时间,定时发送到监控中心。

基本应用

了解了Dubbo的基本概念和工作原理,写个代码试下吧。

本示例采用版本如下:

dubbo:2.7.15

gradle:6.7

代码整体结构如下,一个简单的demo,不复杂。

image.png

dubbo-api

api模块为公共模块,定义一个简单的接口,作为项目依赖供服务者和消费者使用。


public interface HelloService {

    String sayHello(String name);

    default String sayGoodbye(String name) {
        return "Goodbye, " + name;
    }
}

dubbo-provider

服务提供者,定义接口的实现,提供服务。

引入依赖build.gradle

dependencies {
    implementation project(':dubbo-api')
    implementation 'org.apache.dubbo:dubbo:2.7.15'
    implementation 'org.apache.dubbo:dubbo-dependencies-zookeeper:2.7.15'
}

服务提供者的配置文件provider.properties

# 应用名
dubbo.application.name=dubbo-provider
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 使用的协议
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

服务提供者启动类ProviderApplication.java

@Configuration
@EnableDubbo
@PropertySource("classpath:provider.properties")
public class ProviderApplication {
    public static void main(String[] args) throws Exception {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderApplication.class);
        context.start();

        System.out.println("dubbo service started.");
        new CountDownLatch(1).await();
    }
}

对接口的实现HelloServiceImpl.java

@DubboService
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        System.out.println("provider received invoke of sayHello: " + name);
        return "Hello, " + name;
    }

    public String sayGoodbye(String name) {
        System.out.println("provider received invoke of sayGoodbye: " + name);
        return "Goodbye, " + name;
    }
}

dubbo-consumer

服务消费者

同样的先引入依赖build.gradle

dependencies {
    implementation project(':dubbo-api')
    implementation 'org.apache.dubbo:dubbo:2.7.15'
    implementation 'org.apache.dubbo:dubbo-dependencies-zookeeper:2.7.15'
}

服务消费者的配置文件provider.properties

# 应用名
dubbo.application.name=dubbo-consumer
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

服务消费者启动类ConsumerApplication.java

@Configuration
@EnableDubbo
@ComponentScan
@PropertySource("classpath:consumer.properties")
public class ConsumerApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerApplication.class);
        context.start();
        ConsumerService consumerService = (ConsumerService) context.getBean("consumerService");
        consumerService.sayHello();
        consumerService.sayGoodbye();
    }
}

定义一个service,用来调用dubbo服务。

@Service
public class ConsumerService {

    @DubboReference
    private HelloService helloService;

    public void sayHello() {
        String result = helloService.sayHello("world");
        System.out.println(result);
    }

    public void sayGoodbye() {
        String result = helloService.sayGoodbye("world");
        System.out.println(result);
    }
}

结束

到此,一个简单的dubbo小项目就实现了。