Dubbo源码学习总结系列一 总体认识

        本文写作时,dubbo最高版本是V2.6.0。  写这篇文章主要想回答以下4个问题:

        一、dubbo是什么?完成了哪些主要需求?

        二、dubbo适用于什么场景?

        三、dubbo的总体架构是什么样的?

        四、dubbo调用的过程是什么样的?

        下面就一一道来。

    

        一、dubbo是什么?完成了哪些主要需求?

        dubbo是一个面向服务治理(SOA)的分布式RPC框架。

        它主要实现了以下一些需求:

        RPC方面:

        实现了基本的RPC过程,开发了DubboProtocol作为默认的实现,并集成了Hession,RMI,HTTP,WebService,Thrift(被改造,与原Thrift不兼容),Rest等远程过程调用框架。基本组成为:Protocol(默认dubbo),Invoker,Transporter(默认netty),Codec2(默认Hession2编码)。

        编解码方面提供了Hession2(默认,阿里修改过的hessian lite)、dubbo、Java、JSON、Thrift(与原Thrift不兼容)、Kryo、FST序列化。

        DubboProtocol实现了同步调用、异步请求、回调方法设置、本地调用等等灵活的调用特性。

        服务治理方面:

        1、实现了集群、容错、负载均衡及路由策略

        2、实现了注册功能,完成提供者、消费者注册、订阅通知策略等;

        3、对外提供了服务提供者、消费者配置信息、调用链、依赖关系的展现接口,并可以对服务提权、降级,配置路由信息等针对服务的治理手段;

        4、开发了服务管理控制台dubbo-admin,可以在此查看服务相关注册信息,对服务实施治理;

        5、开发了服务监控台dubbo-monitor,可查看服务实时调用情况,包括调用次数,调用时间,吞吐量等统计信息,实时查看服务的健康状况,作为服务治理手段的依据。

 

        二、dubbo适用于什么场景?

        1、业务中需要高吞吐量、复杂的RPC调用,有服务治理需求的场景;

        2、有轻量级微服务化需求的场景;

        下面引用dubbo用户手册的需求描述来说明什么情况下需要用到dubbo:

        

        在大规模服务化之前,应用可能只是通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过 F5 等硬件进行负载均衡。

        当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。

        当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。 这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。

        接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

        以上是 Dubbo 最基本的几个需求。

 

        三、dubbo的总体架构是什么样的?

        调用关系说明:

        

        0、服务容器在启动时启动、加载服务提供者;

        1、启动时,服务提供者向注册中心注册服务;

        2、启动时,服务消费者向注册中心订阅服务;

        3、注册中心给消费者返回服务提供者的地址列表,的提供者服务有什么变动,将用长连接推送变动数据给订阅者;

        4、服务消费者发起对提供者服务的调用,提供者返回调用结果给消费者;

        5、服务消费者和提供者在内存中累计调用次数和调用时间,每分钟发送一次统计数据给监控中心Monitor,供监控中心统计查询。

        Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

 

        总体设计:

        

        此图在学习源码前看的眼花缭乱,学习之后看一目了然。

        

        图例说明:

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

        各层说明:

  • config 配置层:对外配置接口,以 ServiceConfigReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以ServiceProxy 为中心,扩展接口为 ProxyFactory
  • registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为RegistryFactoryRegistryRegistryService
  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 ClusterDirectoryRouterLoadBalance
  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为MonitorFactoryMonitorMonitorService
  • protocol 远程调用层:封将 RPC 调用,以 InvocationResult 为中心,扩展接口为 Protocol,InvokerExporter
  • exchange 信息交换层:封装请求响应模式,同步转异步,以 RequestResponse 为中心,扩展接口为 ExchangerExchangeChannelExchangeClientExchangeServer
  • transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel,TransporterClientServerCodec
  • serialize 数据序列化层:可复用的一些工具,扩展接口为 SerializationObjectInput,ObjectOutputThreadPool

 

        关系说明:

  • 在 RPC 中,Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点。
  • 图中的 Consumer 和 Provider 是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓普节点,保持统一概念。
  • 而 Cluster 是外围概念,所以 Cluster 的目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。
  • Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。
  • 而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。
  • Registry 和 Monitor 实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。

        模块分包:

     

 

        模块说明:

  • dubbo-common公共逻辑模块,提供了各种Util类,通用模块。
  • dubbo-remoting远程通讯模块,主要实现DubboProtocol底层通讯细节(用RMI协议,此包没用),包含的接口有:Transaction(传输层),Exchange数据交换层等;
  • dubbo-rpc远程调用模块,实现Protocol,Invoker, Exporter等上层协议接口定义,实现DubboProtocol协议的上层实现,以及DubboCodec类(dubbo编码)实现;封装了Hession协议、RMI协议、Http协议、WebService协议、Rest协议、Thrift等协议的实现;抽象了动态代理,只包含一对一的调用,不关心集群的管理。
  • dubbo-cluster集群模块,将多个提供方伪装成一个服务方,定义了Cluster集群接口、容错接口、Loadbalance负载均衡接口、Route接口,Directry目录接口,并提供了以上接口的各种实现。集群的地址列表可以是静态配置的,也可以是由注册中心下发。
  • dubbo-register注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
  • dubbo-config配置模块,实现服务提供者和消费者的配置定义加载。
  • dubbo-container容器模块,实现了启动时的服务提供者和消费者启动、加载、初始化。一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。
  • dubbo-monitor 监控模块:统计服务调用次数,调用时间的,调用链跟踪的服务。

        整体上按照分层结构进行分包,与分层的不同点在于:

  • container 为服务容器,用于部署运行服务,没有在层中画出。
  • protocol 层和 proxy 层都放在 rpc 模块中,这两层是 rpc 的核心,在不需要集群也就是只有一个提供者时,可以只使用这两层完成 rpc 调用。
  • transport 层和 exchange 层都放在 remoting 模块中,为 rpc 调用的通讯基础。
  • serialize 层放在 common 模块中,以便更大程度复用。

        四、dubbo调用的过程是什么样的?

        调用链:

        展开总设计图的红色调用链,如下:

 

 

        暴露服务时序图:

        展开总设计图左边服务提供方暴露服务的蓝色初始化链,时序图如下:

 

        引用服务时序图:

        展开总设计图右边服务消费方引用服务的蓝色初始化链,时序图如下:

 

        注:以上大量引用了dubbo的develop手册的文字和图片内容。

posted on 2018-02-18 18:08  滴水穿石,写自己的故事  阅读(1311)  评论(0编辑  收藏  举报

导航