Dubbo系列 - 整体架构

概述

文章内容参考infoq以及其他博文综合整理而来,具体参考的文章如下:

架构概览图

Dubbo系列 - 整体架构

Dubbo系列 - 整体架构

  • Provider导出一个服务,这个服务就是可被调用的;

  • 第二步,往注册中心注册这个服务;

  • Consumer 这端会来订阅相关的服务,如果注册中心里面,Provider 列表有变化的话,它也会得到通知;

  • Consumer 会根据一定的路由规则从注册中心拿到 Provider 列表,再根据一定的负载均衡策略,精确地调用到某台 Provider 上去。

问题或改进点

案例

在杭州有一家中等规模的电商公司,公司内部有 4000+ 个服务,以 Zookeeper 作为注册中心,Zookeeper 有 100w 个节点,在发布日的时候,公司内部网络的网卡被打爆了,进而导致服务变更的推送失败,新的服务注册也失败。整个集群基本上处于不可用状态。同样的也收到了一些中小公司的反馈,每次在发布的时候,网络也会有个抖动。

分析一下为什么会出现这种情形。

Zookeeper 的 100 万节点中,大约有 10 万个 Provider 节点和 50 万个 Consumer 节点。按照前面的算法,在所有 Provider 同时发布的极端情况下,有 2×10 万×50 万次推送,也就是说会产生 1000 亿条的数据推送。针对每次推送的数据进行了一个统计,每条 URL 大小大概有 1KB,那么计算出来的极端的推送数据量是 1KB 再乘以 1000 亿,已经是 100TB 的级别了。

主要原因:

  • zk上的URL内的内容非常多,URL内包含,机器信息,应用信息,接口信息以及方法等。在极端情况下,应用上下线都要通知provider,会造成网络堵塞,导致服务不可用。

解决方案

  • 注册中心只保存ip和端口。

  • url等信息存储到一个持久化存储,拆分出元数据中心。

Dubbo系列 - 整体架构

讨论理想的注册中心?

  • Eureka,AP应用,性能zk的60%,是应用注册维度,而非目前服务注册维度。

  • Etcd,CP系统,要求数据强一致性,牺牲了部分性能。

  • zookeeper, 中心化,leader单点,CP系统,选举中有最多30秒不可用。

  • Nacos,去中心化,设计上满足AP和最终一致性,性能与ZK接近。(比较理想的方案,原理: https://www.infoq.cn/article/B*6vyMIKao9vAKIsJYpE

Nacos应该是比较理想的一个服务注册中心,github地址: https://github.com/alibaba/nacos

Nacos一致性协议:

目前的一致性协议实现,一个是基于简化的 Raft 的 CP 一致性,一个是基于自研协议 Distro 的 AP 一致性。Raft 协议不必多言,基于 Leader 进行写入,其 CP 也并不是严格的,只是能保证一半所见一致,以及数据的丢失概率较小。Distro 协议则是参考了内部 ConfigServer 和开源 Eureka,在不借助第三方存储的情况下,实现基本大同小异。Distro 重点是做了一些逻辑的优化和性能的调优。

三个中心

Dubbo系列 - 整体架构

期望的使用方式:Provider 先去配置中心里获取注册中心的地址和元数据中心地址,再根据拿到的注册中心地址去对应的注册中心注册服务,根据拿到的元数据中心地址写入元数据信息到对应的元数据中心 Server。Consumer 和 OPS 也是类似的。

设计原则

拓展站点设计原则:http://dubbo.apache.org/zh-cn/docs/dev/principals/extension.html

设计基本常识:http://dubbo.apache.org/zh-cn/docs/dev/principals/general-knowledge.html

扩展:http://dubbo.apache.org/zh-cn/docs/dev/principals/expansibility.html

源码导读入口:http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html

整体架构设计

Dubbo系列 - 整体架构

图例说明:

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

各层说明

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

领域模型

在 Dubbo 的核心领域模型中:

  • Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。
  • Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
  • Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。

基本设计原则

  • 采用 Microkernel + Plugin 模式,Microkernel 只负责组装 Plugin,Dubbo 自身的功能也是通过扩展点实现的,也就是 Dubbo 的所有功能点都可被用户自定义扩展所替换。
  • 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。