华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发

华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发

文章图片

华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发

文章图片

华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发

文章图片

华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发

文章图片


假设你正在参与公司一项非常重要的项目开发 , 在做需求沟通时 , 要求系统在分布式场景下实现高并发、高可扩展、自动容错和高可用 , 如果这个项目由你主导 , 你会怎么做呢?
在分布式场景下 , 可能最先想到的是分布式通信的问题 , 在Google或国内网站上搜索分布式RPC框架 , 就会搜索到Dubbo 。
一般熟悉一个框架 , 首先会查阅官网 , 然后下载最新代码 , 仔细阅读代码示例或新手指南 , 最后动手编写代码或打开示例代码 , 在开发工具中快速运行 。 如果已经有不错的编程经验 , 那么或许能顺利“跑通” , 如果是编程新手则可能被一些配置或编译错误难倒 。
编写分布式场景下高并发、高可扩展的系统对技能的要求很高 , 因为其中涉及序列化/反序列化、网络、多线程、设计模式、性能优化等众多专业知识 。 Dubbo框架很好地将这些专业知识做了更高层的抽象和封装 , 提供了各种开箱即用的特性 , 让用户可以“傻瓜式”地使用 。

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

  • Dubbo核心协议;
  • 扩展点SPI;
  • 线程模型;
  • 注册中心;
  • 关注点分离(解耦业务和框架) 。
Dubbo是阿里SOA服务化治理方案的核心框架 , 每天为2000多个服务提供30多亿次访问量支持 , 并被广泛应用于阿里集团的各成员站点 。 阿里重启开源计划主要有以下几个原因:
  • 战略 , 云栖大会宣布拥抱开源的发展策略;
  • 社区 , 社区反馈的问题得不到及时解决 , 聆听社区的声音能够激发灵感;
  • 生态 , 繁荣的生态普惠所有人;
  • 回馈 , 分享阿里在服务治理、大流量、超大规模集群方面的经验 。
自从2017年7月重启Dubbo开源 , Star数增长7428+ ,Fork数增长3072+ ,Watch数增加745+ , 同时社区生态也在不断壮大发展 。 Dubbo在GitHubJava类项目中Star数排名前10位(Star数为21.5K+)荣获开源中国2017年最受欢迎中国开源软件TOP3(Java类项目第一) 。
在分布式RPC框架中 , Dubbo是Java类项目中卓越的框架之一 , 它提供了注册中心机制 , 解耦了消费方和服务方动态发现的问题 , 并提供高可靠能力 , 大量采用微内核+富插件设计思想 ,
在我们深入了解Dubbo框架之前 , 请仔细阅读框架的架构和关键特性 , 如下图所示 。 其中有一些是技术性的 , 更多的是关于架构和设计哲学 , 在探索Dubbo的过程中 , 我们会多次探讨它们 。

上图中Provider启动时会向注册中心把自己的元数据注册上去(比如服务IP和端口等) , Consumer在启动时从注册中心订阅(第一次订阅会拉取全量数据)服务提供方的元数据 , 注册中心中发生数据变更会推送给订阅的Consumer 。 在获取服务元数据后 , Consumer可以发起RPC调用 , 在RPC调用前后会向监控中心上报统计信息(比如并发数和调用的接口) 。


Dubbo解决什么问题随着互联网应用规模不断发展 , 单体和垂直应用架构已经无法满足需求 , 分布式服务架构及流动计算架构势在必行 , 需要一个治理系统确保架构不断演进 , 架构演进请参考下图 。

我们先来回顾一下不同应用架构之间的区别 。
  • 单一应用架构:当网站流量很小时 , 只需一个应用 , 将所有功能都部署在一起 , 以减少部署节点和成本 。 此时 , 用于简化增删改查工作量的数据访问框架(ORM)是关键 。
  • 垂直应用架构:当访问量逐渐增大时 , 单一应用增加机器带来的加速度越来越小 , 将应用拆成互不相干的几个应用 , 以提升效率 。 此时 , 用于加速前端页面开发的Web框架(MVC)是关键 。
  • 分布式服务架构:当垂直应用越来越多时 , 应用之间的交互是不可避免的 , 将核心业务抽取出来 , 作为独立的服务 , 逐渐形成稳定的服务中心 , 使应用能更快速地响应多变的市场需求 。 此时 , 用于提高业务复用及整合的分布式服务(RPC)框架是关键 。
  • 流动计算架构:当服务越来越多时 , 容量的评估、小服务资源的浪费等问题逐渐显现 , 此时需增加一个调度中心基于访问压力实时管理集群容量 , 提高集群利用率 。 此时 , 用于提高机器利用率的资源调度和治理中心是关键 。
随着服务规模和架构的不断演进 , 在大规模服务化之前 , 应用可能只是通过RMI或Hessian等工具简单地暴露和引用远程服务 , 通过配置服务的URL地址进行调用 , 通过F5等硬件进行负载均衡 。 当服务规模不断膨胀后 , 使用Dubbo能为用户解决什么问题呢?Dubbo着眼于解决如下几个最基本的问题:
高性能、透明的RPC调用 。 只要涉及服务之间的通信 , RPC就必不可少 。 Dubbo 可以让开发者像调用本地的方法一样调用远程服务 , 而不需要显式在代码中指定是远程调用 。 整个过程对上层开发者透明 , Dubbo 会自动完成后续的所有操作 , 例如:负载均衡、路由、协议转换、序列化等 。 开发者只需要接收对应的调用结果即可 。
自动负载与容错 。 当服务越来越多时 , F5硬件负载均衡器的单点压力也越来越大 。 Dubbo提供了完整的集群容错机制 , 可以实现软件层面的负载均衡 , 以此降低硬件的压力 。 Dubbo还提供了调用失败的各种容错机制 , 如Failover、Failfast、 结果集合并等 。
服务的自动注册与发现 。 当服务越来越多时 , 服务URL配置管理变得非常困难 , 服务的注册和发现已经不可能由人工管理 。 此时需要一个服务注册中心 , 动态地注册和发现服务 , 使服务的位置透明 。 Dubbo适配了多种注册中心 , 服务消费方(消费者)可以通过订阅注册中心 , 及时地知道其他服务提供者的信息 , 全程无须人工干预 。
动态流量调度 。 在应用运行时 , 某些服务节点可能因为硬件原因需要减少负载;或者某些节点需要人工手动下线;又或者需要实现单元化的调用、灰度功能 。 Dubbo提供了管理控制台 , 用户可以在界面上动态地调整每个服务的权重、路由规则、禁用/启用 , 实现运行时的流量调度 。
依赖分析与调用统计 。 当应用规模进一步提升 , 服务间的依赖关系变得错综复杂甚至分不清哪个应用要在哪个应用之前启动 , 架构师都不能完整地描述应用的架构关系 。 服务的调用量越来越大 , 服务的容量问题就暴露出来 , 这个服务需要多少机器支撑?什么时候该加机器? Dubbo 可以接入三方APM做分布式链路追踪与性能分析 , 或者使用已有的独立监控中心来监控接口的调用次数及耗时 , 用户可以根据这些数据反推出系统容量 。
Dubbo后续的规划我们在Dubbo官方的规划中 , 清楚地知道后续Dubbo的发展趋势 。 Dubbo的核心发展规划如下:
  • 模块化 。 解决通信层与服务治理层耦合严重的问题 , 为DubboMesh做好准备 。
  • 大流量 。 通过熔断、隔离、限流等手段来提升集群整体稳定性 , 定位故障节点 。
  • 元数据 。 服务治理数据和服务注册数据的分离 , 解决元数据冗长的问题 , 为对接注册中心、配置中心做好准备 。
  • 大规模 。 超大规模集群应对服务注册发现、内存占用、CPU消耗带来的挑战 。
  • 路由策略 。 引入在阿里内部广泛实践的路由策略:多机房、灰度、参数路由等智能化策略 。
  • 异步化 。 CompletableFuture 支持 , 跨进程的Reactive 支持 , 提升分布式系统整体的吞吐率和CPU利用率 。
  • 生态扩展 。 在API、注册、集群容错等各个层次 , 兼容并适配现有主流的开源组件 , 如Spring Boot、Hystrix 等 。
  • 生态互通 。 Dubbo在未来还会发布各种其他语言的client如PHP、Python、 Nodejs 。
  • 【华为p30|高性能RPC通信框架——Dubbo详解,深入浅出带你进军Java开发】云原生 。 Dubbo 后续会向Dubbo Mesh 方向发展 , 让服务治理能力下沉 , 成为平台的基础能力 , 应用无须与特定的语言技术栈绑定 , 让DubboMesh成为数据面板 。
  • 多语言支持 。 通过将服务治理能力sidecar化 , 支持多种语言的RPC已经成为可能 , 这也是Spring Cloud方案的最大短板 。
Dubbo总体分层Dubbo的总体分为业务层(Biz)、 RPC层、Remote 三层 。 如果把每一层继续做细分 , 那么一共可以分为十层 。 其中 , Monitor层在最新的官方PPT中并不再作为单独的一层 。 如下图所示 , 图中左边是具体的分层 , 右边是该层中比较重要的接口 。

Service和Config两层可以认为是API层 , 主要提供给API使用者 , 使用者无须关心底层的实现 , 只需要配置和完成业务代码即可;后面所有的层级合在一起 , 可以认为是SPI层 , 主要提供给扩展者使用 , 即用户可以基于Dubbo框架做定制性的:二次开发 , 扩展其功能 。 Dubbo的扩展能力非常强 , 这也是Dubbo一直广受欢迎的原因之一 。 后续笔者将会有介绍Dubb的扩展机制 。
每一层都会有比较核心的接口来支撑整个层次的逻辑 , 后续如果读者需要阅读源码 , 则可以从这些核心接口开始 , 梳理整个逻辑过程 。 在后面的章节中 , 我们会围绕不同的层次对其原理进行讲解 。
Dubbo核心组件Dubbo框架中的分层代表了不同的逻辑实现 , 它们是一个个组件 , 这些组件构成了整个Dubbo体系 , 在使用方角度更多接触到的可能是配置 , 更多底层构件被抽象和隐藏了 , 同时提供了非常高的扩展性 。 Dubbo框架之所以能够做到高扩展性 , 受益于各个组件职责分明的设计 , 每个组件提供灵活的扩展点 ,

Dubbo总体调用过程或许有读者目前还不能理解整个组件串起来的工作过程 , 因此我们先介绍一下服务的暴露过程 。 首先 , 服务器端(服务提供者)在框架启动时 , 会初始化服务实例 , 通过Proxy 组件调用具体协议( Protocol ) , 把服务端要暴露的接口封装成Invoker (真实类型是AbstractProxyInvoker) , 然后转换成Exporter , 这个时候框架会打开服务端口等并记录服务实例到内存中 , 最后通过Registry 把服务元数据注册到注册中心 。 这就是服务端(服务提供者)整个接口暴露的过程 。 大家可能对里面的各种组件还不清楚 , 下面就讲解组件的含义:
  • Proxy组件:我们知道 , Dubbo 中只需要引用一个接口就可以调用远程的服务 , 并且只需要像调用本地方法一样调用即可 。 其实是Dubbo框架为我们生成了代理类 , 调用的方法其实是Proxy 组件生成的代理方法 , 会自动发起远程/本地调用 , 并返回结果 , 整个过程对用户完全透明 。
  • Protocol:顾名思义 , 协议就是对数据格式的一种约定 。它可以把我们对接口的配置 , 根据不同的协议转换成不同的Invoker对象 。 例如:用DubboProtocol可以把XML文件中一个远程接口的配置转换成-个DubboInvoker 。
  • 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的 , 因此在调用最终的实现类之前 , 又会经过一个服务提供者端的过滤器链 。
最终 , 我们得到了具体接口的真实实现并调用 , 再原路把结果返回 。
至此 , 一个完整的远程调用过程就结束了 。
总结以上就是小编整理的dubbo简介 , 同时介绍了Dubbo提供的特性 。 我们了解了国内有很多大公司都在使用Dubbo目前Dubbo又重启维护 , 社区不断在成长与壮大 。
然后 , 我们概述了Dubbo 的总体架构图和核心组件 , 并把所有核心组件合在一起 , 讲解Dubbo的一次总体调用的过程 。
喜欢文章请多多点赞评论转发 , 关注笔者 , 后续笔者会再带来更丰富的学习内容更新 。 你们的支持就是笔者最大的动力!!!


    推荐阅读