一、服务暴露


如何实现java工程暴露metric给prometheus java暴露服务接口_开发语言

图1 暴露原理图

 

整体来看,DUbbo的服务暴露部分分为两个部分:

将持有的服务实例通过代理转换成Invoker。
将Invoker通过具体的协议(比如Dubbo框架中的Dubbo协议)转换成Exporter。
Dubbo中的所有模型都会向Invoker靠拢,向它发起invoke调用,他的实现可能是本地、远程、集群三种,因此,本文服务暴露准备从远程和本地两个角度来讲。、

2.1 远程服务暴露

对于远程服务暴露,流程如下:

服务暴露前,根据上下文的配置覆盖策略进行配置。
服务暴露入口于ServciceConfig.doExportUrls()方法,主要做这么几件事:

  • 2.1 获得服务仓库(存储了所有服务端发布的服务、客户端需要访问的服务)。
  • 2.2 注册当前所需发布的服务(即接口)和服务提供者到服务仓库中。
  • 2.3 获取服务注册与发现的服务URL列表
  • 2.4 遍历每个协议,进行服务发布,根据服务的名称+group+版本号进行服务URL映射,并将其作为元数据的服务key。
  • 2.5 发布当前协议的服务到服务的注册与发现中心,调用doExportUrlsFor1Protocol()方法。

doExportUrlsFor1Protocol()方法中,主要做这么几件事:

  • 3.1 获取协议名称,并且创建一个用于存储配置参数的集合map。
  • 3.2 将配置信息、运行时配置、泛化配置、验证信息等加入到map中。
  • 3.3 将当前服务的IP、监听的端口和参数map整合成一个请求URL。
  • 3.4 进行配置的扩展。
  • 3.5 获取当前发布服务所配置的scope属性值,判断当前服务发布返回的是远程还是本地。
  • ----3.5.1 若 scope的值是"none" 或者不是"remote" ,那就发布到本地,请看下面的本地服务暴露流程。
  • ----3.5.2 否则进行远程发布,看3.6↓
  • 3.6 循环所有处理过的注册中心地址进行发布,获取当前dubbo服务URL中的proxy参数
  • 3.7 将服务实例ref通过动态代理的方式转换成Invoker,(包含Exporter)。
  • 3.8 服务暴露后通过Exporter向注册中心注册服务信息,调用PROTOCOL.export(wrapperInvoker)方法

对于export()方法,远程暴露先调用的是RegistryProtocol.export()方法,主要做五件事:

  • 4.1 委托具体协议(Dubbo)进行服务暴露,创建NettyServer监听端口和保存服务实例。
  • 4.2 创建注册中心对象,与注册中心创建TCP连接(Netty实现)。
  • 4.3 注册服务元数据到注册中心。
  • 4.4 订阅configurators节点,监听服务动态属性变更事件(通过覆盖订阅的监听器来实现,进行数据覆盖更新)。
  • 4.5 服务销毁收尾工作,比如关闭端口、反注册服务信息等(通过发布器的包装类实例来实现,包含Invoker的销毁方法)。

进行参数配置,然后根据每个服务进行服务暴露。
将每个服务ref通过动态代理的方式转换成一个Invoker,再通过Invoker来获得Exporter对象。
Exporter进行服务的具体暴露,会通过Netty(默认实现)来和注册中心搭建一个TCP连接,负责监听数据的更新并且进行数据覆盖。
暴露完成后,再进行元数据的注册(就是往Zookeeper上创建一个节点)。
进行服务销毁的收尾工作。
对于本地服务暴露,流程如下:

显式的指定injvm协议进行暴露,协议改为"injvm", IP改成"127.0.0.1", 端口改为"0"。
通过返回InjvmExporter实例对象,将当前Invoker加入exporterMap,进行本地的缓存。

服务的发现原理


如何实现java工程暴露metric给prometheus java暴露服务接口_java_02

图2 服务消费原理

整体来看,Dubbo做服务消费也分成两个部分:

  1. 通过持有的远程服务实例来生成Invoker,即远程代理对象。
  2. 把Invoker通过动态代理转换成实现用户接口的动态代理引用。

服务消费的入口在ReferenceBean类下的getObject方法中,主要负责dubbo引用ref进行初始化,即通过配置参数去创建一个代理类,然后赋值给ref属性。
调用方法Protocol.refer(),根据接口的类型、载入的注册中心地址进行ref的注入。Protocol是一个自适应扩展点,此时的自适应扩展其实就是被包装的RegistryProtocol实现,即调用RegistryProtocol.refer()方法。
其中会根据协议类型来创建对应的注册中心实例,并根据容错策略来合并Invoker。
对于合并的每一个Invoker,通过监听器去进行具体的实现,如设置基本的服务路由链,进行当前服务的订阅等操作。最终合并到Cluster集群中然后返回。
将服务的元数据进行保存,默认会写入到本地。
使用服务引用生成的invoker来构建一个代理类。(默认是使用javassist技术来构建)。
精简总结可得:

Dubbo要想调用一个服务,需要对对应服务进行引用ref的初始化。
初始化则根据接口类型、URL地址的不同来进行属性注入(不同的Invoker)。
每个Invoker又会进行对应的服务注册和订阅,并将对应服务的元数据进行保存(默认写入本地)。
Dubbo会根据容错策略将多个Invoker(若服务同时配置多个注册中心)合并成一个并返回。
通过动态代理的方式,通过Invoker返回引用ref,完成初始化。