分布式RPC框架Apache Dubbo(上)

106 阅读19分钟

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

分布式RPC框架Apache Dubbo

学习目标

1、了解软件架构的演进过程

2、熟悉Dubbo框架的架构执行流程

3、了解RPC远程调用过程

1. 软件架构的演进过程

软件架构的发展经历了由单体架构、垂直架构、SOA架构到微服务架构的演进过程,下面我们分别了解一下这几个架构。

1.1 单体架构

1590747754277.png 特点: all in one

①所有功能集中在一个项目中
​
②所有功能都要达成war包部署到服务器
​
③ 通过集群(session共享集群)来提高服务器的性能

优点: ①.项目架构简单,前期开发的成本低,周期短,小型企业首先.

缺点: ①全部的功能都集中在一个项目中完成,对于大型项目来说,开发难度高,不容易开发及扩展和维护

1.2 垂直架构

1590747897948.png 架构说明:

按照业务进行切割,形成小的单体项目。

特点:
    ①.以单体架构为单位进行系统的划分,划分成一个个系统.
    ②.项目与项目之间独立开发,开发效率高.
    ③.项目是以接口调用为主
优点:
    ①.项目架构简单,前期开发的成本低,周期短,小型企业首先.
    ②.垂直架构进行mvc分层设计,针对分层做相应的处理做到集群(10~1000)
    ③.不同的项目采用不同的技术实现.
    
缺点:
    ①.全部的功能都集中在一个项目中完成,对于大型项目来说,开发难度高,不容易开发及扩展和维护.
    ②.集群扩展有瓶颈集群
    ②.项目与项目之间存在数据冗余,耦合度高.
    ②.项目是以接口调用为主,存在数据同步问题.

1.3 SOA架构

SOA全称为Service-Oriented Architecture,即面向服务的架构

它可以根据需求通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用。

一个服务通常以独立的形式存在于操作系统进程中。

站在功能的角度,把业务逻辑抽象成可复用的服务,通过服务的编排实现业务的快速再生,

目的:把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用。

1590748540358.png 架构说明:

将重复功能或模块抽取成组件的形式,对外提供服务,在项目与服务之间使用ESB(企业服务总线)的形式作为通信的桥梁。

特点: ①.基于soa服务思想进行功能的抽取(重复代码问题解决),以服务为中心来管理项目. ②.各个系统之间要进行调用,所以出现ESB来管理项目(可以使用各种技术实现:webservice,rpc等) ③.ESB是作为系统与系统之间桥梁,进行统一管理.

优点: ①.重复代码进行了抽取,提高了开发效率,提高了系统的可维护性. ②.可以针对某个系统进行扩展,做集群更容易. ③.采用ESB来管理服务组件,有利于降低企业开发项目难度

缺点: ①.系统与服务的界限模糊的,不利于设计. ②.ESB是作为系统与系统之间桥梁,没有统一标准,种类很多,不利于维护!

常见的企业服务总线:

  1. IBM WebSphere ESB
  2. Microsoft ESB
  3. JBOSS SOA Platform等等

1.4 微服务架构

1590748637827.png 架构说明:

  • 将系统服务层完全独立出来,抽取为一个一个的微服务。
  • 抽取的粒度更细,遵循单一原则。
  • 采用轻量级框架协议传输。

特点:

    ①.把系统的服务层完全独立出来,有利于资源的重复利用,提高开发效率.
    ②.微服务遵守单一原则
    ③.微服务与微服务之间的调用使用restful轻量级调用.

优点:

①.微服务拆分更细,有利于资源的重复利用,提高开发效率
②.可以更加精准针对某个服务做方案
③.微服务去中心化,使用restful轻量级通信协议比使用ESB企业服务总线更容易维护
④.适应市场更容易,产品迭代周期更短.

缺点:

    微服务量多,服务治理成本高,不利于系统维护
    分布式系统架构且是微服务架构,技术成本高(容错,分布式事务等),对团队高挑战

2. Apache Dubbo概述

2.1 Dubbo简介

- 2.7之前alibaba,从2.7之后是apache
- Apache Dubbo是一款高性能(NIO)的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。- 2018年2月9日,Apache 基金会的邮件列表上发起了讨论是否接纳阿里的 Dubbo 项目进入 Apache 孵化器的投票。- 2018年2月15日,邮件列表显示,Dubbo 获得了 14 张赞成票,在无弃权和反对票的情况下,正式通过投票,顺利成为 Apache 基金会孵化项目。

官网地址:dubbo.apache.org/en-us/

dubbo的版本说明
​
Apache Dubbo是一款应用广泛的高性能轻量级的Java 远程调用分布式服务框架,支持多种通信协议。当网站安装了Apache Dubbo并且启用http协议进行通信时,攻击者可以向网站发送POST请求,在请求里可以执行一个反序列化的操作,由于没有任何安全校验,这个反序列化过程可以执行任意代码。这里,序列化是指把某个编程对象转换为字节序列的过程,而反序列化是指把字节序列恢复为某个编程对象的过程。
​
漏洞影响的Apache Dubbo产品版本包括:2.7.0~2.7.4、2.6.0~2.6.7、2.5.x 的所有版本。
​
- Apache Dubbo官方建议用户网站升级到安全的2.7.5版本。

什么是RPC?

RPC全称为remote procedure call,即远程过程调用

比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。

需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程

RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。各种开发语言都有自己的RPC框架。Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。

Dubbo官网地址:dubbo.apache.org

Dubbo提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

本章节我们会先学习dubbo的远程调用技术。负载均衡和容错后续项目2继续学习!

Dubbo高性能的底层实现技术:

性能提升NIO
  • 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中
  • Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
  • Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
Netty框架

Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

Dubbo基于 Netty框架开发的高性能分布式RPC框架

2.2 Dubbo架构

Dubbo 框架

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:

  • 面向接口的远程方法调用,
  • 智能容错和负载均衡
  • 服务自动注册和发现

Dubbo框架的通信层 - 利用Netty的实现过程

Dubbo架构图(Dubbo官方提供)如下:

2.png 节点角色说明:

节点角色名称
Provider服务提供方 - 服务的提供者 类似 商家
Consumer服务消费方 - 使用服务的一方 类似买家
Registry服务注册与发现的注册中心 - 类似京东
Monitor统计服务的调用次数和调用时间的监控中心 - 类似京东后台
Container服务运行容器

虚线都是异步访问,实线都是同步访问 蓝色虚线:在启动时完成的功能 红色虚线(实线)都是程序运行过程中执行的功能

调用关系说明:

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

3. Dubbo快速入门开发(了解)

参照官网文档: API代码可以从官方直接拷贝

dubbo.apache.org/zh-cn/docs/…

3.1 基于API接口的快速入门案例

目标:理解rpc调用以及注册中心

实现步骤说明

1.服务提供方独立jvm运行,暴露服务接口
    开发步骤:
    a.创建应用配置
    b.创建协议配置
    c.服务接口暴露
2.服务消费方找到服务接口,并进行调用
    开发步骤:
    a.创建应用配置
    b.引用调用接口

打开下发资料,使用idea工具打开

1600348209215.png 模块说明:

  • father 父模块
  • api 服务接口模块
  • consumer 服务消费模块
  • provider 服务提供者模块

father模块:

father:pom引入maven依赖:

说明: 初始案例采用服务器直连数据传输,没有注册中心,先不导入zookeeper依赖

 <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.5</version>
        </dependency>
    </dependencies>

子模块:api模块

新建接口:HelloService

1600348346496.png

public interface HelloService {
​
    public String  sayHello(String hello);
}
​

子模块:provider

pom 依赖通用服务接口模块 api

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

新建接口实现类:

1600348393545.png

public class HelloServiceImpl implements HelloService {
    public String sayHello(String hello) {
        return "provider :"+hello;
    }
}

导入日志文件: resources目录下

1600348460371.png

3.1服务提供方开发

创建一个服务启动类: 根据官方文档 api 代码示例: 直接拷贝

package cn.itcast.provider;
​
import cn.itcast.service.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
​
import java.io.IOException;
​
public class App {
​
    public static void main(String[] args) throws Exception {
        // 服务实现
        HelloService helloService= new HelloServiceImpl();
​
// 当前应用配置
        ApplicationConfig application = new ApplicationConfig();
        application.setName("provider-dubbo");
​
// 连接注册中心配置 -  无配置中心  点对点连接
        RegistryConfig registry = new RegistryConfig(RegistryConfig.NO_AVAILABLE);
​
// 服务提供者协议配置
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("dubbo");
        protocol.setPort(20880);
​
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口// 服务提供者暴露服务配置
        ServiceConfig<HelloService> service = new ServiceConfig<HelloService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
        service.setApplication(application);
        service.setRegistry(registry); // 多个注册中心可以用setRegistries()
        service.setProtocol(protocol); // 多个协议可以用setProtocols()
        service.setInterface(HelloService.class);
        service.setRef(helloService);
        service.setVersion("1.0.0");
​
// 暴露及注册服务
        service.export();
​
        //  模拟服务启动--  当前线程阻塞
        System.in.read();
    }
}

log4j.properties日志打印:

#############
# 输出到控制台
#############
log4j.rootLogger=INFO,CONSOLE,logfile
# 配置CONSOLE输出到控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 
# 配置CONSOLE设置为自定义布局模式
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 
# 配置CONSOLE日志的输出格式  [frame] 2019-08-22 22:52:12,000  %r耗费毫秒数 %p日志的优先级 %t线程名 %C所属类名通常为全类名 %L代码中的行号 %x线程相关联的NDC %m日志 %n换行
log4j.appender.CONSOLE.layout.ConversionPattern=[frame] %d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p [%t] %C:%L %x - %m%n

运行main方法:

1600348652718.png 暴露的url地址为:dubbo://192.168.148.1:20880/com.itheima.dubbo.HelloService?anyhost=true&application=app-provider&bind.ip=192.168.148.1&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.itheima.dubbo.HelloService&methods=sayHello&pid=7716&release=2.7.6&side=provider&timestamp=1597373499709

3.2服务消费方开发

1600348682715.png pom

依赖服务接口模块 api

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

新建消费方测试类:

package cn.itcast.consumer;
​
import cn.itcast.service.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
​
public class App {
    public static void main(String[] args) {
        // 当前应用配置
        ApplicationConfig application = new ApplicationConfig();
        application.setName("consumer-dubbo");
​
// 连接注册中心配置 -  不适用注册中心
        RegistryConfig registry = new RegistryConfig(RegistryConfig.NO_AVAILABLE);
​
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接// 引用远程服务
        ReferenceConfig<HelloService> reference = new ReferenceConfig<HelloService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
        reference.setApplication(application);
        reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
        reference.setInterface(HelloService.class);
        reference.setVersion("1.0.0");
// 如果点对点直连,可以用reference.setUrl()指定目标地址,设置url后将绕过注册中心,
// 将服务端日志发布的url地址拷贝到setUrl方法参数中
        reference.setUrl("dubbo://192.168.3.12:20880/cn.itcast.service.HelloService");
​
// 和本地bean一样使用xxxService
        HelloService helloService = reference.get(); 
        // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
​
        String heima = helloService.sayHello("heima");
​
        System.out.println(heima+"===============");
​
    }
}
​

调用结果:

1600348169137.png

3.3开发流程小结

3.3.1 RPC基本概念

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。

两个独立进程间的相互调用, 解决:服务和服务之间的数据传输问题!rpc调用网络通讯部分根据协议不同,采用的数据传输报文不同。

远程调用过程:

  • RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务

通俗的描述是:客户端调用存在于远程计算机上的某个对象,就像调用本地应用程序中的对象一样

3.3.2api接口核心类

类名描述
ApplicationConfig应用配置
ProtocolConfig协议配置
RegistryConfig注册中心配置
ServiceConfig服务暴露配置,通过方法export暴露服务接口
ReferenceConfig引用调用配置,通过get方法获取对应的代理对象,调用接口就和本地方法调用一样

3.3.3 思考

问:消费端直接就使用接口调用,没有任何的实现类去实现可以调用成功吗?
​
- 答:java程序中如果遇到直接使用接口调用,除了有具体实现类外,还可以通过动态代理来实现。那么在dubbo中就是采用了动态代理机制,源码跟踪:ReferenceConfig.get() --> init() ---> ref = createProxy(map);
如下图:
消费端通过生成代理类: 将消费端的配置参数封装到map中,通过底层netty 发送给服务端, 
当调用服务接口方法时,获取服务端回送的数据!
​
问:刚才的案例中我们在客户端通过硬编码的方式指定url地址,如果我们暴露的服务有多个,同时线上运行的服务提供者有多个,那么我们这种在代码里面写死url地址会引来一些问题,
如:1.服务提供者可能新增,也可能删除,2.服务端提供的接口不可能这么简单,线上环境是批量的多个接口,那么我们如果要每一个接口引用都去写死地址那开发效率就很低了。有没有什么好的解决方案吗?
​
- 答:引入注册中心来对我们的服务进行统一管理维护,让消费端自己主动发现服务。

1600348875660.png

3.4 使用zookeeper注册中心

我们接着在项目的maven 父工程的配置文件pom.xml中引入zkclient依赖:

       <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
        </dependency>

3.4.1 服务提供方

我们前面在注册中心配置属性设置的是不使用注册中心,接下来我们使用zookeeper作为我们的服务注册中心,配置如:

RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");

修改后的完整代码:

package cn.itcast.provider;
​
import cn.itcast.service.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
​
import java.io.IOException;
​
public class ServiceApp {
​
    public static void main(String[] args) throws Exception {
        // 服务实现
        HelloService helloService= new HelloServiceImpl();
​
// 当前应用配置
        ApplicationConfig application = new ApplicationConfig();
        application.setName("provider-dubbo");
​
// 连接注册中心配置
//        RegistryConfig registry = new RegistryConfig(RegistryConfig.NO_AVAILABLE);
        RegistryConfig registry = new RegistryConfig("zookeeper://127.0.0.1:2181");
​
// 服务提供者协议配置
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("dubbo");
        protocol.setPort(20880);
​
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口// 服务提供者暴露服务配置
        ServiceConfig<HelloService> service = new ServiceConfig<HelloService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
        service.setApplication(application);
        service.setRegistry(registry); // 多个注册中心可以用setRegistries()
        service.setProtocol(protocol); // 多个协议可以用setProtocols()
        service.setInterface(HelloService.class);
        service.setRef(helloService);
        service.setVersion("1.0.0");
​
// 暴露及注册服务
        service.export();
​
        //  模拟服务启动--  当前线程阻塞
        System.in.read();
    }
}
​

dubbo发布服务源码说明:

扩展内容: 关于dubbo服务注册zookeeper源码出处

  1. service.export(); 方法跟踪:

1601166111776.png 找到实现者: ListenerRegistryWrapper.java 实现 register方法,继续跟进

1601166496215.png 找到发布服务具体实现: FailbackRegistry接口的 具体实现者完成服务发布!

断点跟踪: ZookeeperRegistry 调用 ZkClient完成节点的创建!

1603770467730.png 其中:

create 方法 创建临时节点

toUrlPath(url) 对地址进行编码 特殊字符处理

URLEncoder.encode(url, "UTF-8");//  自动对特殊字符进行编码转义

url.getParameter() -- true 表示创建:临时节点

3.4.2 服务消费方

package cn.itcast.consumer;
​
import cn.itcast.service.HelloService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
​
import java.io.IOException;
​
public class ConsumerApp {
    public static void main(String[] args) throws IOException {
        // 当前应用配置
        ApplicationConfig application = new ApplicationConfig();
        application.setName("consumer-dubbo");
​
// 连接注册中心配置 -  不适用注册中心
//        RegistryConfig registry = new RegistryConfig(RegistryConfig.NO_AVAILABLE);
        RegistryConfig registry = new RegistryConfig("zookeeper://127.0.0.1:2181");
​
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接// 引用远程服务
        ReferenceConfig<HelloService> reference = new ReferenceConfig<HelloService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
        reference.setApplication(application);
        reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
        reference.setInterface(HelloService.class);
        reference.setVersion("1.0.0");
// 如果点对点直连,可以用reference.setUrl()指定目标地址,设置url后将绕过注册中心,
// 将服务端日志发布的url地址拷贝到setUrl方法参数中
//        reference.setUrl("dubbo://192.168.3.12:20880/cn.itcast.service.HelloService");// 和本地bean一样使用xxxService
        HelloService helloService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
​
        String heima = helloService.sayHello("heima");
        System.out.println(heima+"===============");
        System.in.read();
    }
}
​

扩展内容: 服务消费:从注册中心获取服务地址

源码: doInvoke() 方法处添加断点:

DubboInvoker 作用:获取zookepper中心发布的服务节点并且调用底层对象完成数据传输!

1601170990139.png 在该构造方法中,参数URL中包含了服务端节点数据,

追踪。。。。是由ZookeeperRegister对象doSubscribe方法,获取zookeeper节点数据!

1601170000965.png ZookeeperRegister.java找到 doSubscribe方法 中:--- 对象 中: 获取 服务端发布的服务节点信息:

源码: 191行处: 获取zookeeper中心服务端临时节点:

1601172428365.png 193行代码: 将服务端的地址 特殊字符进行转换

1601171893203.png toUrlsWithoutEmpty方法: 将获取服务节点地址进行地址解析!

1601171374045.png 至此: 消费端源码解析完成!

接下来我们只需要测试 服务端和消费端数据交互即可!

3.4.3 启动zookeeper

1600356369407.png 先后重新启动 生产者和消费者

1600356464042.png

在客户端 zkCli.cmd 端 执行查询命令:

ls /dubbo -R 发现生产者和消费已经注册到zookeeper中心上

1600356400811.png

3.5 dubbo官方架构图(扩展)

如果想深入学习dubbo,可以参照dubbo官方框架流程图:

dubbo.apache.org/zh-cn/docs/…

1601172782636.png

图例说明

  • 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
  • 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。
  • 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。
  • 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。

各层说明

  • config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
  • registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
  • protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
  • exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
  • serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

3.6 阶段小结

  • dubbo和zookeeper各自的作用:

    • dubbo底层通过rpc实现系统之间的数据通信
    • zookeeper实现服务端和消费端节点的存储