【微服务】dubbo源码阅读(一)

目录

1.简介

1.1 背景知识

1.2 应用场景

3.流程

3.1服务提供者服务导出

3.2 服务消费者调用服务

4.源码模块解析

4.1 包组织结构

4.2 层次结构

4.2.1 config配置

4.2.2 *Proxy 服务代理层

4.2.3 Registry注册中心层 

4.2.4 Cluster 路由层 

4.2.5 Protocol远程调用层

4.2.6 Exchange信息交换层 

4.2.7 Serialize数据序列化层 


1.简介

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

类似与Spring mvc 是http层的框架,使用http协议进行通信并调用http web服务 @requestMapping暴露的接口,Dubbo可以基于TCP+自定义协议调用服务暴露出来的远程方法。

1.1 背景知识

  • 远程调用 : RMI、hassian、webservice、thrift 
  • 通信交互 : HTTP、mina、netty
  • 序列化 : hessian2、 java、json
  • 容器 : jetty、spring
  • 多线程 : 异步、线程池
  • 服务注册发现 : zookeeper、redis

1.2 应用场景

  • 作为对内提供服务应用的容器
  • 拆分复杂Web应用到服务容器
  • 应用负载均衡协调
  • 应用服务治理

3.流程

0.start 容器启动     1.register:服务提供者启动-注册       2.subscribe:服务消费者启动-订阅注册中心 

3.notify:注册中心通知消费者 有新的服务提供者

4.invoke:RPC远程调用

5.count:监控

3.1服务提供者服务导出

服务提供者配置如下

<beans>
    <!-- 服务提供者的应用程序名称,用于跟踪依赖关系 -->
    <dubbo:application name="demo-provider"/>

    <!-- 利用注册中心导出服务 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- 使用dubbo协议在端口20880上导出服务 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- 服务实现,方式与常规bean一样 -->
    <bean id="demoService" class="demo.DemoServiceImpl"/>

    <!-- 声明要导出的服务接口 -->
    <dubbo:service interface="demo.DemoService" ref="demoService"/>
</beans>

首先ServiceConfig类拿到对外提供服务的实际类ref(如上配置:DemoServiceImpl),然后通过ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化。

接下来就是Invoker转换到Exporter的过程,如下图,通过Protocol的export方法导出服务,并注册到注册中心
/dev-guide/images/dubbo-export.jpg

DubboProtocol,以上的暴露的服务

url=dubbo://xx.xx.xx.xxx:20880/demo.DemoService?anyhost=true&application=demo-provider&bind.ip=xx.xx.xx.xxx&bind.port=20880&channel.readonly.sent=true&codec=dubbo&dubbo=2.6.2&generic=false&interface=demo.DemoService&methods=sayHello&pid=30185&side=provider&timestamp=1575978129988

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        exporterMap.put(key, exporter);

        ...

        openServer(url);
        optimizeSerialization(url);
        return exporter;
    }

3.2 服务消费者调用服务

首先ReferenceConfiginit方法调用Protocolrefer方法

生成Invoker实例(如上图中的红色部分),

这是服务消费的关键。

接下来把Invoker转换为客户端所需接口(如:DemoService)。

每种协议如RMI/Dubbo/Web service等它们在调用refer方法

生成Invoker实例的细节。

/dev-guide/images/dubbo-refer.jpg

design-step-4/dev-guide/images/dubbo-extension.jpg

核心方法refersubscribe()

4.源码模块解析

4.1 包组织结构

/dev-guide/images/dubbo-modules.jpg

  • dubbo-common 公共逻辑模块:包括 Util 类和通用模型。
  • dubbo-remoting 远程通讯模块:相当于 Dubbo 协议的实现,如果 RPC 用 RMI协议则不需要使用此包。
  • dubbo-rpc 远程调用模块:抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。
  • dubbo-cluster 集群模块:多个provider包成一个,负载均衡, 容错,路由等,集群地址列表可静态配置,也可由注册中心下发。
  • dubbo-registry 注册中心模块:基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
  • dubbo-monitor 监控模块:统计服务调用次数,调用时间的,调用链跟踪的服务。
  • dubbo-config 配置模块:是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。
  • dubbo-container 容器模块:是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。

4.2 层次结构

https://img-blog.csdnimg.cn/20190826143519959.png

  • Service()服务层:业务实现,包含服务提供者和消费者的实现类和接口类
  • Config配置层(dubbo-config): 服务代理层,主要结合SPI机制,动态选取不通的配置类,参见SPI机制
  • Registry注册层(dubbo-registry) :负责注册和发现Dubbo服务,以及对Dubbo服务的监听
  • Cluster路由层(dubbo-cluster):服务的路由、负载和失败重试策略
  • Protocol协议层(dubbo-rpc):协议的转换和过滤
  • Exchange信息交换层 (dubbo-remoting) 
  • Transport传输层(dubbo-remoting):抽象Netty、Mina为统一接口,数据通信传输
  • Serialize序列化层(dubbo-common):根据不同协议对数据进行序列化

4.2.1 config配置

负责所有dubbo相关的xml配置和注释配置转换为config对象 ( dubbo.xsd )

api配置的对象类,用于生成对应的register,protocol等对象

核心类有

  • ServiceBean(对应provider端的<dubbo:service interface="demo.DemoService" ref="demoService"/>)
  • ReferenceBean (consumer端的<dubbo:reference id="demoService" check="false" interface="demo.DemoService"/>)
  • ProtocolConfig(provider端的<dubbo:protocol name="dubbo" port="20880"/>)
  • RegisterConfig (<dubbo:registry address="zookeeper://127.0.0.1:2181"/>)

4.2.2 *Proxy 服务代理层

负责生成消费者的代理对象,以及服务提供方Provider的Invoker
ProxyFactory接口的2种实现 JdkProxyFactory、JavassistProxyFactory,原理请见动态代理

Proxy层封装了所有接口的透明化代理,而在其它层都以Invoker为中心,只有到了暴露给用户使用时,才用Proxy将Invoker转成接口,或将接口实现转成Invoker,也就是去掉Proxy层RPC是可以Run的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。

4.2.3 Registry注册中心层 

负责服务注册与查询服务,以及注册服务的本地缓存<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
支持多种协议注册发现服务,例如redis、zookeeper、Multicast

核心类
接口 RegistryFactoryRegistry
AbstractRegistry 以及 ZookeeperRegistryZookeeperRegistryFactory

以zk为例

支持以下功能:

当提供者出现断电等异常停机时,注册中心能 自动删除 提供者信息。
当注册中心重启时,能 自动恢复 注册数据,以及订阅请求。
当会话过期时,能 自动恢复 注册数据,以及订阅请求。
当设置 < dubbo:registry check=" false " /> 时,记录失败注册和订阅请求,后台定时重试。

流程说明:

  1. 提供者启动时向/dubbo/com.foo.BarService/providers目录下写入自己的URL地址。
  2. 消费者启动时订阅/dubbo/com.foo.BarService/providers的提供者URL地址。并向/dubbo/com.foo.BarService/consumers下写入自己的URL地址。
  3. 监控中心启动时订阅/dubbo/com.foo.BarService目录下的所有提供者和消费者URL地址。

4.2.4 Cluster 路由层 

主要负责负载均衡的策略,以及失败策略,缺省设置:RandomLoadBalance,FailoverCluster
支持轮询、随机、最少活跃、一致性哈希负载均衡策略

核心类
接口 LoadBalance、Cluster
RandomLoadBalance以及 RoundRobinLoadBalance等

各节点关系:

Invoker是Provider的一个可调用Service的抽象,Invoker封装了Provider地址及Service接口信息

Directory代表多个Invoker,可以把它看成List<Invoker>,但与List不同的是,它的值可能是动态变化的,比如注册中心推送变更。

Cluster将Directory中的多个Invoker伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个。

Router负责从多个Invoker中按路由规则选出子集,比如读写分离,应用隔离等。

LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。

4.2.5 Protocol远程调用层

封装RPC调用、支持多种RPC协议,不包含IO通信部分
支持Dubbo(默认)、RMI 、Hessian、Http、WebService、thrift等9种RPC调用方式
接口 Protocol、Exporter、Invoker
DubboProtocol、DubboInvoker、DubboExporter、DubboCodec

  1. DubboProtocol采用单一长连接和NIO异步通讯,适用于小数据量大并发的服务调用,及consumer cnt >> provider cnt。通过单一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步IO,复用线程池,防止C10K问题。
  2. dubbo协议底层直接使用了Netty框架,在dubbo协议中,分为三种调用方式:同步(默认)、异步和OneWay,同步就是阻塞等拿到被调用方的结果再返回;异步不等待被调用者的处理结果就直接返回,但需要等到被调用者接收到异步请求的应答;OneWay(单向调用)在很多MQ和RPC框架中都有出现,即调用方只负责调用一次,不管被调用方是否接收到该请求,更不会去理会被调用方的任何应答,OneWay一般只会在无需保证调用结果的时候使用。

4.2.6 Exchange信息交换层 

主要功能:封装请求响应模式,同步转异步,处理各种协议的通信请求,支持netty、mina、http等,默认采用Netty进行通信
接口 ServerChannelClient 
NettyClientNettyServer

4.2.7 Serialize数据序列化层 

数据序列化层和可复用的一些工具,包括序列化线程池等。dubbo协议缺省为hessian2,rmi协议缺省为java,http协议缺省为json
接口 ThreadPoolSerialization 
FixedThreadPoolHessian2Serialization
 

发布了92 篇原创文章 · 获赞 14 · 访问量 5832

猜你喜欢

转载自blog.csdn.net/sarafina527/article/details/103382459