Dubbo3

[TOC]

服务导出

当我们在某个接口上加上@DubboService后,就表示定义了一个Dubbo服务,启动应用的时候就会扫描到,并且解析对应的类,得到相对服务的配置信息:

  1. 服务的类型

  2. 服务的具体实现类

  3. 服务的Version、Timeout等等(也就是@DubboService里面配置的信息)

解析完过后就会把这些配置信息封装成一个ServiceConfig对象,并调用export()进行服务的导出

所谓的服务导出,其实就是做三件事情:

  1. 确定服务的最终参数配置

  2. 按照不同的协议启动不同的服务器

  3. 将服务进行注册,注册到注册中心

确定参数

这一个环节其实就是,确定好我们配置的参数:

  • 在application里面配置的:name、protocol、timout……

  • @DubboService里面配置的: version之类的接口级别的信息

最终确定出服务的各种参数

服务注册

当确定好最终的配置参数过后,Dubbo就会根据配置信息生成对应 服务URL:

URL包括了服务的:ip、port、协议、服务名……

URL也确定了,是时候把这个URL存到注册中心里面去了

但是服务注册不仅仅这样简单了, 他需要注意:

  • 如果配置信息改变了,消费者要如何感知到change

  • 消费者要怎么知道现在他要用的某个Dubbo服务,是哪一个呢

  • ……

应用级注册

在Dubbo3.0之前,Dubbo进行的都是接口级注册,每个接口在注册中心(ZK)上都会有一个字符串

在Dubbo3.0之后,他兼容了以前的接口级注册,但同时提供了应用级的注册:

其中:

key是接口名,value就是服务URL

那么为什么好端端的,要学SpringCloud Nacos那套,应用级注册呢?

来看看:

一个分布式系统接口调用,就会存在就是说:一个应用中有3个Dubbo服务,那么每增加一个实例,就会向注册中心添加3条记录,那如果一个应用中有10个Dubbo服务,那么每增加一个实例,就会向注册中心添加10条记录,注册中i心的压力随着应用实例的增加而剧烈增加。

所以为了降低注册中心的压力,Dubbo3选择支持应用级注册,同时也兼容接口级注册,用户可逐步迁移称应用级注册

上面提到:

消费者要怎么知道现在他要用的某个Dubbo服务,是哪一个呢

在进行服务到处的过程中,会在ZK中存一个映射关系,在服务到导出的最后一步,ServiceConfigexported()方法保存了这个映射关系:

其中mapServiceName(url, serviceNameMapping, scheduledExecutor);保存了映射关系

消费者知道了要使用的Dubbo服务在哪个应用,那也就可以从注册中心中根据应用名查到应用的所有实例信息。但是在真正发送请求之前,还得知道服务的配置信息,对与消费者而言,他得知道当前要调用的这个Dubbo服务支持什么协议、timeout是多少……那么这个配置信息从上面最开始说到了,他们已经被注册到了注册中心了。

那么应用级注册是如何实现的呢?

首先,需要通过配置application里面来选择自己是要接口等级还是应用级注册,,当调用RegistryProtocolexport()方法处理registry://时,会利用ZookeeperRegistry把服务URL注册到Zookeeper中去,这就是接口级注册。

ServiceDiscoveryRegistry里面的doRegistry(URL url)方法,就是应用级注册

这个方法做了两件事情:

  • 将传进来的url进行处理

  • 对处理过后的url进行注册

那么再来看看这个register方法吧:

再进去:

可以看出来,就是吧传进来的url构造出ServiceInfo对象放到services里面,一个MetadataInfo对象就存储以上的信息

前面提到过,在应用启动的最后,才会进行应用级注册,而应用级注册就是当前的应用实例上相关的信息存入注册中心, 包括:

  1. 应用的名字

  2. 获取与应用元数据的方式

  3. 当前实例的ip和port

  4. 当前实例支持的协议以及对应的端口

那么如果存在这样的一种情况呢:一个实例支持多个协议以及多个端口,呢么如何确定实例的ip和port?

就像这样:

如果是这样,最终存入endpoint中的会保证一个协议只对应一个端口,另外那个将被忽略,最终服消费者在进行服务引入的时候就会用到这个endpoint信息

在Dubbo2.7中就有了元数据中心,它其实就是减轻注册中心的压力的,Dubbo会把服务信息完整的存一份到元数据中心,元数据中心也可以用ZK来实现,自傲暴露完元数据服务之后,在注册实例信息到注册中心之前,就会把MetadataInfo存入元数据中心。

总结一下:

  1. 在导出某个Dubbo服务URL时,会把服务URL存入MetadataInfo中(ServiceConfig)

    1. 根据不同的协议,启动不同的服务器

    2. 将URL存入MetadataInfo中

    3. 所有服务都存入过后,将(接口:应用名)存入元数据中心

  2. 应用级注册

    1. Remote:将MedatadaInfo对象存入元数据中心

    2. Local:启动导出元数据服务(默认dubbo协议,端口20880)

      1. 确定实例port

      2. 确定dubbo.endpoints

      3. 确定实例编号revision

      4. 将实例对象存入注册中心

服务引入

服务引入就是通过引入加了@DubboReference注解的类的代理对象

通过ReferenceConfigget()方法得到一个当前接口的代理对象

然后通过RegistryProtocol.doRefer()方法返回一个MigrationInvoker对象:

接着通过MigrationRule.getStep()方法对step进行赋值:

反正最终就是得到一个基于MigrationInvoker的接口代理对象

服务调用

在引入服务之后,通过接口代理对象执行方法:执行MigrationInvoker.invoke()方法,去除currentAvailableInvoker属性对应的ClusterInvoker,然后执行ClusterInvoker.invoke方法,最后通过负载均衡根据不同的协议发送不同的数据包

Last updated