深圳幻海软件技术有限公司 欢迎您!

我们一起跟着Dubbo起飞

2023-02-27

前言Docker这项技术其实大家或多或少都听过的,或者是在你以往投简历的时候,划水刷博客、刷论坛的时候,肯定也见到过这一门技术,你要是真的没听过也没见过,去问百度,Dubbo这个技术应该大家都听说过,有的公司可能项目用的也是Dubbo,这个技术面试应该也会属于一个好手,会了Dubbo,关于RPC的调

前言

Docker这项技术其实大家或多或少都听过的,或者是在你以往投简历的时候,划水刷博客、刷论坛的时候,肯定也见到过这一门技术,你要是真的没听过也没见过,去问百度,Dubbo这个技术应该大家都听说过,有的公司可能项目用的也是Dubbo,这个技术面试应该也会属于一个好手,会了Dubbo,关于RPC的调用也就懂个八九不离十了,网络层面的很多知识点也就一并懂了不少了,总之,接下来呢,要开启的Dubbo系列绝对会让你受益匪浅,一起学习吧!

之前应该也写过不少系列的文章了,我也将这些文章都已经收录到我的https://github.com/DayuMM2021/Java文章网址中去了,这个网址中还包含不少代码,包括设计模式示例、RocketMQ源码解析、Dubbo源码解析,以及后续的大数据分析等等。

这篇文章呢,主要就是带领大家明白Dubbo的来源,作用以及架构设计,我们一般学习一个技术点首先要了解的就是该技术点的来源、做什么的,能够解决哪些痛点问题,大致的架构和运转流程是什么样子的。

千万不要上来直接死磕各种细节,各种源码,否则直接自己把自己搞懵逼了。

你看了这篇文章之后,什么RPC调用啊,什么HTTP啊,这些都将不在话下,不过离彻底搞懂Dubbo还是差了点意思的,但是,只要你坚持的读下去我的Dubbo系列文章,那你可就不一样了。

这波,这波啊我都明示了,老铁们,点赞关注不迷路。

RPC和HTTP

RPC,Remote Procedure Call也就是远程过程调用,指的是计算机程序在不同的地址空间的调用,通常是不同的计算机,RPC是进程间通信的一种形式,因为不同的进程具有不同的地址空间。

如果在同一个主机上,即使物理地址空间是相同的,它们也具有不同的虚拟地址空间,如果位于不同的主机上,则物理地址空间肯定也会不同的,则虚拟地址空间也不会相同了。

远程过程调用对标的是本地过程调用,本地过程调用大家应该都很熟悉的吧,你写了一个简单的Java程序,内部的方法的调用其实就是属于本地过程的调用了,而远程过程调用则指的是本地调用了远程主机上的某个方法,这就是属于远程过程调用了。

RPC和HTTP,傻傻分不清楚

RPC和HTTP不是对等的概念,RPC呢,上面也解释了,属于一个完整的远程调用链路,包括:接口规范+序列化反序列化规范+通信协议等,而HTTP只是属于一个通信协议,属于OSI的第七层,不是一个完整的远程调用链路。

这就是属于牛(HTTP)和马车(RPC)的比较,要想比较,需要给牛一个工具,把它变成牛车!

HTTP的远程调用

基于HTTP的远程调用,HTTP+Restful,优势比较大,可读性好,使用这种方案会包含大量的HTTP头信息,有用信息占比少,这种相对来说应该也是比较麻烦的,需要封装各种参数名和参数值。

Restful属于一种规范,就是一种动作加资源的规范,动作包含GET、POST、PUT、DELETE,资源呢,网络中的一切都是属于资源,这种规范就是对网络中的资源进行各种操作,资源是Restful架构或者说是整个网络处理的核心。

RPC

RPC呢,好处就是有用信息占比很高,效率呢也很高,调用起来也会很简单,就像是调用本地服务一样,没有任何的感知,我们也不需要关心网络传输或者通讯问题,HTTP其实也是属于RPC实现的一种方式,RPC呢,就像是地区方言,只需要内部知道,双方都需要知道方言,不然没办法沟通而已,HTTP就像是普通话,基本都能听得懂。

RPC框架就是要实现小助手一样的功能,目的就是让我们使用远程调用像本地调用一样简单方便,并且可以解决一些远程调用会发生的各种问题,使我们开发人员可以无感知、舒服的开发,它好我也好,快乐无烦恼。

RPC流程

服务A调用服务B的过程对开发人员的感知仿佛是内部调用一样,RPC要求在调用方中放置被调用的方法的接口,调用方只要调用了这些接口,就相当于调用了被调用方的实际方法,很简单,调用方也可以像调用内部接口一样调用远程方法,不需要封装参数名和参数值等操作。

服务A调用服首先,调用方调用的是接口,必须得为接口构造一个假的实现,显然要使用动态代理,这样,调用方的调用就被动态代理接受到了。

动态代理接受到调用之后,要想的就是调用远程的实际实现,包括识别具体调用的远程方法的IP和端口号、调用方法的入参序列化、将请求发送到远程的方法中,远程服务接收到调用方的请求之后的步骤,包括反序列化各个调用参数、定位到实际调用方法,然后输入参数调用、按照调用的路径返回调用的结果。

简单的搞了一张图,大家理解下:

Dubbo来源

很多时候,其实我们使用这个技术的时候,可能都是因为项目需要,所以,我们就用了,但是,至于为什么我们需要用到这个技术,可能自身并不是很了解的,但是,其实了解技术的来由及背景知识,对于理解一项技术还是有帮助的,那么,dubbo是怎么被提上日程的呢?

在互联网的发展过程中,在以前,我们只需要一个服务器,将程序全部打包好就可以,但是,随着流量的增大,常规的垂直应用架构已无法应对,所以,架构就发生了演变。逐渐的应用与应用之间的关系已经十分的复杂了,就会出现以下几个问题:

1、服务越来越多,服务URL配置管理变得非常困难,单点压力也越来越大

2、服务依赖关系逐渐复杂,甚至分不清哪个应用要在哪个应用之前启动

3、服务调用量越来越大,服务的容量问题就会暴露,服务需要多少机器支撑,什么时候该加机器

为了解决这由于架构的演变所产生的问题几个问题,于是,dubbo 产生了。当然,解决这个问题的技术不止 dubbo。

从上面 Dubbo 的服务治理图我们就可以看到,Duboo 很好了解决了上面所出现的一些问题。

所以,当你的系统架构发展到了这种阶段的时候,就需要考虑使用 Dubbo 了。

Dubbo架构

先来看一下官网放出的Dubbo的架构图:

节点角色说明

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

上面那些是Dubbo的主要角色,接下来我们一起来说一下整体的流程,其实Dubbo的架构也是很简单,为啥这样说,你有没有发现这其实很像生产者-消费者模型,只不过是在这个模型上,加上了注册中心和监控中心而已,用于管理提供方的提供的URL,还有管理整个过程。

首先服务提供者Provider启动然后向注册中心注册自己所能够提供的服务,服务消费者Consumer启动向注册中心订阅自己所需要调用的服务,然后注册中心将提供相应的元信息给Consumer,随后Consumer便通过负载均衡选择一个Provider直接调用。

服务提供方的元数据如果变更的话,注册中心会把变更信息推送给服务消费者。

服务提供者和消费者都会在内存中记录调用的次数和时间,然后定时发送统计数据到监控中心用于监控。

这样整个流程应该就很清晰了吧!

Dubbo分层架构

看下Dubbo的分层,来源于网络,我们来看下它的架构设计:

大的层次呢,分为三层,分别是Business业务层、RPC传输和Remoting远程,按照设计呢,又可以分为API层和SPI层,采用的是微内核设计+SPI扩展,使得有特殊需求的接入方式可以自定义扩展,做定制的二次开发。

我们一起来详细的看下每一层的作用,千万不要死记硬背,要适度的去理解即可。

  • Service,服务接口层,和实际的逻辑业务有关,根据服务消费方和服务提供方的业务设计,实现对应的接口
  • Config,对外配置层的接口,主要围绕 ServiceConfig 和 ReferenceConfig,初始化配置信息。
  • Register,服务注册层,封装了服务注册和发现,以服务URL为中心,扩展接口为RegistryFactory、Registry、RegistryService,可能没有服务注册中心,服务提供方直接暴露服务
  • Proxy,代理层,服务提供者还是消费者都会生成一个代理类,使得服务接口透明化,代理层做远程调用和返回结果。
  • Cluster,封装多个提供者的路由和负载均衡,并且连接注册中心,以Invoker为中心,将多个服务提供方组成为一个,实现对服务消费透明
  • Monitor,监控层,负责监控统计RPC的调用时间和次数,以Statistics为中心。
  • Portocol,远程调用层,主要是封装 RPC 调用以Invocation和Result为中心,扩展接口是Protocol、Invoker和Exporter,Protocol是服务接口,负责Invoker的生命周期管理;Invoker是实体,属于Dubbo的核心模块,代表一个可执行体。
  • Exchange,信息交换层,用来封装请求响应模型,同步转异步,以Request和Response为中心。
  • Transport,网络传输层,以Message为中心,抽象成Mina和Netty,抽象了网络传输的统一接口。
  • Serialize,序列化层,将数据序列化成二进制流,当然也做反序列化,扩展接口是erialization。

Dubbo服务暴露

服务暴露就是将所要提供的服务暴露出来,你想啊,一个用户服务模块,需要对外提供一个注册新用户的功能,那你这个服务肯定要暴露出来啊,否则外部接口如何调用你这个服务啊!

大家先理解这个意思,这一块我会单独拎出来说,给大家看Dubbo的源码。

Dubbo服务引用

引用呢,就是@Reference的使用了,使用过Dubbo的应该对这个注解都不陌生吧,在ReferenceConfirg中进行消息的订阅,这个消息订阅就是引用注册表的invoke,并且也创建了一个netty客户端用于交互。

Dubbo服务调用

调用这个invoker代理对象(就是自动注入的service),在dubbo中客户端调用的service是被多次代理后的一个对象,这其中有一个filter代理。

作用呢,就是使用dubbo的容错,并通过负载均衡选择使用注册中心中的哪个服务,最终就是DubboInvoker对象中进行远程调用,这个对象来获取到相应的通道,通过模拟这个接口输入的参数,通过request来进行请求,得到结果之后就会进行解析并且返回结果。

SPI机制

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一种动态替换发现的机制, 举个例子来说, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现即可。

那为什么dubbo不用jdk的SPI呢,而是选择自己去模仿实现一个呢!

这些问题我也会单独开一篇SPI来讲解,总之呢,大家读懂这篇文章之后,关于RPC、HTTP、Dubbo这些技术点之间的关系,以及Dubbo的大体架构这些,大家应该都了解了一些了,关于上面这些没有详细介绍的点,我都会单独拎出来说。

而且我还会带着源码给大家分析,你说你看完还能不会Dubbo,面试还怕问到Dubbo吗?