【Dubbo】高性能 RPC 通信框架

╰半橙微兮° 2023-01-19 08:06 106阅读 0赞

主要内容 :

  • Dubbo 简介 ;
  • Dubbo 总体大图 。

对 Dubbo 总体的介绍 , 有一个总体的认识 。 简单介绍一下 Dubbo, 包括它的发展历史 、 未来方向等 ; 最后讲解 Dubbo 的总体大图 , 通过分层的方式讲解 Dubb 。 的总体架构 , 并介绍 Dubbo 的核心组件及总体流程

1. Dubbo 简介

Dubbo 提供了非常丰富的开箱即用的特性 , 我们会花费大部分时间来挖掘它的能力 , Dubbo是一个分布式高性能的 RPC 服务框架 , 它的核心设计原则 : 微内核 + 插件体系 , 平等对待第三方 。 我们也会探讨 Dubbo 其他方面的内容 , 例如 :

  • Dubbo 核心协议 ;
  • 扩展点 SPI ;
  • 线程模型 ;
  • 注册中心 ;
  • 关注点分离 ( 解耦业务和框架 ) 。

1.1 Dubbo 是什么

Dubbo 是阿里 SOA 服务化治理方案的核心框架 , 每天为 2000 多个服务提供 30 多亿次访问量支持 , 并被广泛应用于阿里集团的各成员站点 。 阿里重启开源计划主要有以下几个原因 :

  • 战略 , 云栖大会宣布拥抱开源的发展策略 ;
  • 社区 , 社区反馈的问题得不到及时解决 , 聆听社区的声音能够激发灵感 ;
  • 生态 , 繁荣的生态普惠所有人 ;
  • 回馈 , 分享阿里在服务治理 、 大流量 、 超大规模集群方面的经验 。

自从 2017 年 7 月重启 Dubbo 开源 , Star 数增长 7428+, Fork 数增长 3072+, Watch 数增加 745+, 同时社区生态也在不断壮大发展 。 Dubbo 在 GitHub Java 类项目中 Star 数排名前 10位 ( Star 数为 2L5K+ ) , 荣获开源中国 2017 年最受欢迎中国开源软件 TOP3 ( Java 类项目第一 ) 。

在分布式 RPC 框架中 , Dubbo 是 Java 类项目中卓越的框架之一 , 它提供了注册中心机制 ,解耦了消费方和服务方动态发现的问题 , 并提供高可靠能力 , 大量采用微内核 + 富插件设计思想 包括框架自身核心特性都作为扩展点实现 , 提供灵活的可扩展能力 。

在我们深入了解 Dubbo 框架之前 , 请仔细阅读框架的架构和关键特性 。 其中有一些是技术性的 , 更多的是关于架构和设计哲学 , 在探索 Dubbo 的过程中 , 我们会多次探讨它们
在这里插入图片描述
Provider 启动时会向注册中心把自己的元数据注册上去 ( 比如服务 IP 和端口等 ) ,Consumer 在启动时从注册中心订阅 ( 第一次订阅会拉取全量数据 ) 服务提供方的元数据 , 注册中心中发生数据变更会推送给订阅的 Consumero 在获取服务元数据后 , Consumer 可以发起 RPC调用 , 在 RPC 调用前后会向监控中心上报统计信息 ( 比如并发数和调用的接口 ) 。

在了解 Dubbo 架构的工作原理前,我们先看一下 Dubbo 所包含的关键特性 ( 包含设计理念 ) ,如表所示
在这里插入图片描述

1.2 Dubbo 解决什么问题

随着互联网应用规模不断发展 , 单体和垂直应用架构巳经无法满足需求 , 分布式服务架构及流动计算架构势在必行 , 需要一个治理系统确保架构不断演进
在这里插入图片描述

我们先来回顾一下不同应用架构之间的区别 。

  • 单一应用架构 : 当网站流量很小时 , 只需一个应用 , 将所有功能都部署在一起 , 以减少部署节点和成本 。 此时 , 用于简化增删改查工作量的数据访问框架 ( ORM ) 是关键 。
  • 垂直应用架构 : 当访问量逐渐增大时 , 单一应用增加机器带来的加速度越来越小 , 将应用拆成互不相干的几个应用 , 以提升效率 。 此时 , 用于加速前端页面开发的 Web 框架 ( MVC ) 是关键 。
  • 分布式服务架构 : 当垂直应用越来越多时 , 应用之间的交互是不可避免的 , 将核心业务抽取出来 , 作为独立的服务 , 逐渐形成稳定的服务中心 , 使应用能更快速地响应多变的市场需求 。 此时 , 用于提高业务复用及整合的分布式服务 ( RPC )框架是关键 。
  • 流动计算架构 : 当服务越来越多时 , 容量的评估 、 小服务资源的浪费等问题逐渐显现 , 此时需增加一个调度中心基于访问压力实时管理集群容量 , 提高集群利用率 。 此时 , 用于提高机器利用率的资源调度和治理中心是关键

随着服务规模和架构的不断演进 , 在大规模服务化之前 , 应用可能只是通过 RMI 或 Hessian 等工具简单地暴露和引用远程服务 , 通过配置服务的 URL 地址进行调用 , 通过 F5 等硬件进行负载均衡 。 当服务规模不断膨胀后 , 使用 Dubbo 能为用户解决什么问题呢 ?

Dubbo 着眼于解决如下几个最基本的问题 :

  • 高性能 、 透明的 RPC 调用 。 只要涉及服务之间的通信 , RPC 就必不可少 。 Dubbo 可以让开发者像调用本地的方法一样调用远程服务 , 而不需要显式在代码中指定是远程调用 。 整个过程对上层开发者透明 , Dubbo 会自动完成后续的所有操作 , 例如 : 负载均衡 、 路由 、 协议转换 、 序列化等 。 开发者只需要接收对应的调用结果即可 。
  • 服务的自动注册与发现 。 当服务越来越多时 , 服务 URL 配置管理变得非常困难 , 服务的注册和发现已经不可能由人工管理 。 此时需要一个服务注册中心 , 动态地注册和发现服务 , 使服务的位置透明 。 Dubbo 适配了多种注册中心 , 服务消费方 ( 消费者 )可以通过订阅注册中心 , 及时地知道其他服务提供者的信息 , 全程无须人工干预 。
  • 自动负载与容错 。 当服务越来越多时, F5 硬件负载均衡器的单点压力也越来越大 。Dubbo 提供了完整的集群容错机制 , 可以实现软件层面的负载均衡 , 以此降低硬件的压力 。 Dubbo 还提供了调用失败的各种容错机制 , 如 Failover 、 Failfast 、 结果集合并等 。
  • 动态流量调度 。 在应用运行时 , 某些服务节点可能因为硬件原因需要减少负载 ;或者某些节点需要人工手动下线 ; 又或者需要实现单元化的调用 、 灰度功能 。Dubbo 提供了管理控制台 , 用户可以在界面上动态地调整每个服务的权重 、 路由规则 、 禁用 / 启用 , 实现运行时的流量调度 。
  • 依赖分析与调用统计 。 当应用规模进一步提升,服务间的依赖关系变得错综复杂 ,甚至分不清哪个应用要在哪个应用之前启动 , 架构师都不能完整地描述应用的架构关系 。 服务的调用量越来越大 , 服务的容量问题就暴露出来 , 这个服务需要多少机器支撑 ? 什么时候该加机器 ? Dubbo 可以接入三方 APM 做分布式链路追踪与性能分析 , 或者使用己有的独立监控中心来监控接口的调用次数及耗时 , 用户可以根据这些数据反推出系统容量

1.3 Dubbo 后续的规划

我们在 Dubbo 官方的规划中 , 清楚地知道后续 Dubbo 的发展趋势 。 Dubbo 的核心发展规划如下 :

  • 模块化 。 解决通信层与服务治理层耦合严重的问题 , 为 Dubbo Mesh 做好准备 。
  • 大流量 。 通过熔断 、 隔离 、 限流等手段来提升集群整体稳定性 , 定位故障节点 。
  • 元数据 。 服务治理数据和服务注册数据的分离 , 解决元数据冗长的问题 , 为对接注册中心 、 配置中心做好准备 。
  • 大规模 。 超大规模集群应对服务注册发现 、 内存占用 、 CPU 消耗带来的挑战 。
  • 路由策略 。 引入在阿里内部广泛实践的路由策略 : 多机房 、 灰度 、 参数路由等智能化味:峪 。
  • 异步化 。 CompletableFuture 支持 , 跨进程的 Reactive 支持 , 提升分布式系统整体的吞吐率和 CPU 利用率 。
  • 生态扩展 。 在 API 、 注册 、 集群容错等各个层次 , 兼容并适配现有主流的开源组件 ,如 Spring Boot 、 Hystrix 等 。
  • 生态互通 。 Dubbo 在未来还会发布各种其他语言的 client, 如 PHP 、 Python > Node.jso
  • 云原生 。 Dubbo 后续会向 Dubb 。 Mesh 方向发展 , 让服务治理能力下沉 , 成为平台的基础能力 , 应用无须与特定的语言技术栈绑定 , 让 Dubbo Mesh 成为数据面板 。
  • 多语言支持 。 通过将服务治理能力 sidecar 化 , 支持多种语言的 RPC 已经成为可能 ,这也是 Spring Cloud 方案的最大短板 。

2 Dubbo 总体大图

本节首先介绍整个 Dubbo 的总体大图 , 讲解 Dubbo 的分层结构 , 每一层所做的事情 , 让读者对整个 Dubbo 的框架有个初步了解 。 然后介绍 Dubbo 现有的一些核心组件及总体流程 。

2.1 Dubbo 总体分层

Dubbo 的总体分为业务层 ( Biz) 、 RPC 层 、 Remote H 层 。 如果把每一层继续做细分 , 那么一共可以分为十层 。 其中 , Monitor 层在最新的官方 PPT 中并不再作为单独的一层 。 如图所示 , 图中左边是具体的分层, 右边是该层中比较重要的接口
在这里插入图片描述
Service 和 Config 两层可以认为是 API 层 , 主要提供给 API 使用者 , 使用者无须关心底层的实现 , 只需要配置和完成业务代码即可 ; 后面所有的层级合在一起 , 可以认为是 SPI 层 , 主要提供给扩展者使用 , 即用户可以基于 Dubbo 。 框架做定制性的二次开发 , 扩展其功能 。 Dubbo的扩展能力非常强 , 这也是 Dubbo 一直广受欢迎的原因之一 。 后续会有专门介绍 Dubbo的扩展机制 。

每一层都会有比较核心的接口来支撑整个层次的逻辑 , 后续如果读者需要阅读源码 ,则可以从这些核心接口开始 , 梳理整个逻辑过程 。 在后面的章节中 , 我们会围绕不同的层次对其原理进行讲解 。

3.2 Dubbo 核心组件

Dubbo 框架中的分层代表了不同的逻辑实现 , 它们是一个个组件 , 这些组件构成了整个Dubbo 体系 , 在使用方角度更多接触到的可能是配置 , 更多底层构件被抽象和隐藏了 , 同时提供了非常高的扩展性 。 Dubbo 框架之所以能够做到高扩展性,受益于各个组件职责分明的设计 每个组件提供灵活的扩展点
在这里插入图片描述

3.3 Dubbo 总体调用过程

或许有读者目前还不能理解整个组件串起来的工作过程 , 因此我们先介绍一下服务的暴露过程 。

首先 , 服务器端 ( 服务提供者 ) 在框架启动时 , 会初始化服务实例 , 通过 Proxy 组件调用具体协议 ( Protocol ) , 把服务端要暴露的接口封装成 Invoker ( 真实类型是AbstractProxylnvoker ) , 然后转换成 Exporter, 这个时候框架会打开服务端口等并记录服务实例到内存中 , 最后通过 Registry 把服务元数据注册到注册中心 。 这就是服务端 ( 服务提供者 )整个接口暴露的过程 。 读者可能对里面的各种组件还不清楚 , 下面就讲解组件的含义

  • Proxy 组件 : 我们知道 , Dubbo 中只需要引用一个接口就可以调用远程的服务 , 并且只需要像调用本地方法一样调用即可 。 其实是 Dubbo 框架为我们生成了代理类 , 调用的方法其实是 Proxy 组件生成的代理方法 , 会自动发起远程 / 本地调用 , 并返回结果,整个过程对用户完全透明 。
  • Protocol : 顾名思义 , 协议就是对数据格式的一种约定 。 它可以把我们对接口的配置,根据不同的协议转换成不同的 Invoker 对象 。 例如 : 用 DubboProtocol 可以把 XML 文件中一个远程接口的配置转换成一个 Dubbolnvoker
  • Exporter : 用于暴露到注册中心的对象 , 它的内部属性持有了 Invoker 对象 , 我们可以认为它在 Invoker 上包了 一层 。
  • Registry : 把 Exporter 注册到注册中心 。

以上就是整个服务暴露的过程 , 消费方在启动时会通过 Registry 在注册中心订阅服务端的元数据 ( 包括 IP 和端口 ) 。 这样就可以得到刚才暴露的服务了 。

下面我们来看一下消费者调用服务提供者的总体流程 , 我们此处只介绍远程调用 , 本地调用是远程调用的子集 , 因此不在此展开 。 Dubbo 组件调用总体流程如图所示
在这里插入图片描述
首先 , 调用过程也是从一个 Proxy 开始的 , Proxy 持有了一个 Invoker 对象 。 然后触发 invoke调用 。 在 invoke 调用过程中 , 需要使用 Cluster, Cluster 负责容错 , 如调用失败的重试 。 Cluster在调用之前会通过 Directory 获取所有可以调用的远程服务 Invoker 列表 ( 一个接口可能有多个节点提供服务 ) 。 由于可以调用的远程服务有很多 , 此时如果用户配置了路由规则 ( 如指定某些方法只能调用某个节点 ) , 那么还会根据路由规则将 Invoker 列表过滤一遍 。

然后 , 存活下来的 Invoker 可能还会有很多 , 此时要调用哪一个呢 ? 于是会继续通过LoadBalance 方法做负载均衡 , 最终选出一个可以调用的 Invoker 。 这个 Invoker 在调用之前又会经过一个过滤器链 , 这个过滤器链通常是处理上下文 、 限流 、 计数等 。

接着 , 会使用 Client 做数据传输 , 如我们常见的 Netty Client 等 。 传输之前肯定要做一些私有协议的构造 , 此时就会用到 Codec 接口 。 构造完成后 , 就对数据包做序列化 ( Serialization ) ,然后传输到服务提供者端 。 服务提供者收到数据包 , 也会使用 Codec 处理协议头及一些半包 、粘包等 。 处理完成后再对完整的数据报文做反序列化处理 。

随后 , 这个 Request 会被分配到线程池 ( ThreadPool ) 中进行处理 。Server 会处理这些Request根据请求查找对应的 Exporter ( 它内部持有了 Invoker ) 。 Invoker 是被用装饰器模式一层一层套了非常多 Filter 的 , 因此在调用最终的实现类之前 , 又会经过一个服务提供者端的过滤器链 。

最终 , 我们得到了具体接口的真实实现并调用 , 再原路把结果返回 。

至此 , 一个完整的远程调用过程就结束了 。

发表评论

表情:
评论列表 (有 0 条评论,106人围观)

还没有评论,来说两句吧...

相关阅读

    相关 RPC框架——Dubbo

    Dubbo简介 Dubbo是用来实现分布式RPC调用的框架。 Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。

    相关 RPC框架】之 Dubbo

    一、分布式基础理论 -------------------- 1、什么是分布式系统 《分布式系统原理与范型》定义: 分布式系统是若干独立计算机的集合,这些计算机