乐趣区

关于java:朋友国企干了5年java居然不知道Dubbo是做什么呢我真信了

前言

接下来一段时间敖丙将带大家开启缓和刺激的 Dubbo 之旅!是的要开始写 Dubbo 系列的文章了,之前我曾经写过一篇架构演进的文章,也阐明了微服务的普及化以及重要性,服务化场景下随之而来的就是服务之间的通信问题,那服务间的通信脑海中想到的就是 RPC,说到 RPC 就离不开咱们的 Dubbo。

这篇文章敖丙先带着大家来 总览全局,一般而言相熟一个框架你要先晓得这玩意是做什么的,能解决什么痛点,外围的模块是什么,大抵运行流程是怎么的。

你要一来就扎入细节之中无法自拔,一波 DFS 间接被劝退的可能性高达 99.99%,所以本暖男敖丙将带大家先过一遍 Dubbo 的简介、总体分层、外围组件以及大抵调用流程

不仅如此我还会带着大家过一遍如果要让你 设计一个 RPC 框架你看看都须要什么性能?这波操作之后你会发现嘿嘿 Dubbo 怎么设计的和我想的一样呢?真是英雄所见略同啊!

而且我还会写一个简略版 RPC 框架实现,让大家明确 RPC 到底是如何工作的。

如果看了这篇文章你要还是不晓得 Dubbo 是啥,我能够要劝退了。

咱们先来谈一谈什么叫 RPC,我发现有很多同学不太理解这个概念,还有人把 RPC 和 HTTP 来进行比照。所以咱们先来说说什么是 RPC。

什么是 RPC

RPC,Remote Procedure Call 即近程过程调用,近程过程调用其实对标的是本地过程调用,本地过程调用你相熟吧?

想想那青葱岁月,你在大学赶着期末大作业,正在攻克图书管理系统,你奋笔疾书疯狂地敲击键盘,实现了图书借阅、图书偿还等等模块,你实现的一个个办法之间的调用就叫本地过程调用。

你要是和我说你实现图书馆里零碎曾经用了服务化,搞了近程调用了,我只能和你说你有点货色。

简略的说本机上外部的办法调用都能够称为本地过程调用,而近程过程调用实际上就指的是你本地调用了近程机子上的某个办法,这就是近程过程调用。

所以说 RPC 对标的是本地过程调用,至于 RPC 要如何调用近程的办法能够走 HTTP、也能够是基于 TCP 自定义协定。

所以说你探讨 RPC 和 HTTP 就不是一个层级的货色。

RPC 框架就是要实现像那小助手一样的货色,目标就是让咱们应用近程调用像本地调用一样简略不便,并且解决一些近程调用会产生的一些问题,使用户用的无感知、舒心、释怀、顺心,它好我也好,高兴没懊恼。

如何设计一个 RPC 框架

在明确了什么是 RPC,以及 RPC 框架的目标之后,咱们想想如果让你做一款 RPC 框架你该如何设计?

服务消费者

咱们先从消费者方 (也就是调用方) 来看须要些什么,首先消费者面向接口编程,所以须要得悉有哪些接口能够调用,能够通过 专用 jar 包 的形式来保护接口。

当初晓得有哪些接口能够调用了,然而只有接口啊,具体的实现怎么来?这事必须框架给解决了!所以还 须要来个代理类 ,让消费者只管调,啥事都别管了,我 代理帮你搞定

对了,还须要通知代理,你调用的是哪个办法,并且参数的值是什么。

虽说代理帮你搞定然而代理也须要晓得它到底要调哪个机子上的近程办法,所以 须要有个注册核心,这样调用方从注册核心能够通晓能够调用哪些服务提供方,一般而言提供方不止一个,毕竟只有一个挂了那不就没了。

所以提供方个别都是集群部署,那调用方须要通过 负载平衡 来抉择一个调用,能够通过 某些策略 例如同机房优先调用啊啥的。

当然还须要有 容错机制,毕竟这是近程调用,网络是不牢靠的,所以可能须要重试什么的。

还要和服务提供方 约定一个协定,例如咱们就用 HTTP 来通信就好啦,也就是大家要讲一样的话,不然可能听不懂了。

当然序列化必不可少,毕竟咱们本地的构造是“平面”的,须要序列化之后能力传输,因而还须要 约定序列化格局

并且这过程两头可能还须要掺入一些 Filter,来作一波对立的解决,例如调用计数啊等等。

这些都是框架须要做的,让消费者像在调用本地办法一样,无感知。

服务提供者

服务提供者必定要 实现对应的接口 这是毋庸置疑的。

而后须要把本人的接口裸露进来,向 注册核心注册本人,裸露本人所能提供的服务。

而后有消费者申请过去须要解决,提供者须要用和消费者 协商好的协定 来解决这个申请,而后做 反序列化

序列化完的申请应该 扔到线程池外面做解决 ,某个线程承受到这个申请之后找到对应的实现调用,而后再 将后果原路返回

注册核心

下面其实咱们都提到了注册核心,这货色就相当于一个平台,大家在下面裸露本人的服务,也在下面得悉本人能调用哪些服务。

当然还能做配置核心,将配置集中化解决,动静变更告诉订阅者。

监控运维

面对泛滥的服务,精细化的监控和不便的运维必不可少。

这点很多开发者在开发的时候觉察不到,到你真正上线开始运行保护的时候,如果没有良好的监控措施,疾速的运维伎俩,到时候就是睁眼瞎!不知所措,等着挨批把!

那种苦楚不要问我为什么晓得,我就是晓得!

小结一下

让咱们小结一下,大抵上一个 RPC 框架须要做的就是约定要通信协议,序列化的格局、一些容错机制、负载平衡策略、监控运维和一个注册核心!

简略实现一个 RPC 框架

没错就是简略的实现,下面咱们在思考如何设计一个 RPC 框架的时候想了很多,那算是生产环境应用级别的性能需要了,咱们这是 Demo,目标是突出 RPC 框架重点性能 – 实现近程调用

所以啥七七八八的都没,并且我用伪代码来展现,其实也就是删除了一些保护性和约束性的代码,因为看起来太多了不太直观,须要一堆 try-catch 啥的,因而我删减了一些,直击重点。

Let’s Do It!

首先咱们定义一个接口和一个简略实现。

`public interface AobingService {
    String hello(String name);  

public class AobingServiceImpl implements AobingService {
    public String hello(String name) {
        return “Yo man Hello,I am” + name;  
    }  
}`

而后咱们再来实现服务提供者裸露服务的性能。

`public class AobingRpcFramework {
     public static void export(Object service, int port) throws Exception {
          ServerSocket server = new ServerSocket(port);
          while(true) {
              Socket socket = server.accept();
              new Thread(new Runnable() {
                  // 反序列化
                  ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 
                  String methodName = input.read(); // 读取办法名
                  Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); // 参数类型
                  Object[] arguments = (Object[]) input.readObject(); // 参数
                  Method method = service.getClass().getMethod(methodName, parameterTypes);  // 找到办法
                  Object result = method.invoke(service, arguments); // 调用办法
                  // 返回后果
                  ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                  output.writeObject(result);
              }).start();
          }
     }
    public static <T> T refer (Class<T> interfaceClass, String host, int port) throws Exception {
       return  (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass}, 
            new InvocationHandler() {  
                public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
                    Socket socket = new Socket(host, port);  // 指定 provider 的 ip 和端口
                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); 
                    output.write(method.getName());  // 传办法名
                    output.writeObject(method.getParameterTypes());  // 传参数类型
                    output.writeObject(arguments);  // 传参数值
                    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());  
                    Object result = input.readObject();  // 读取后果
                    return result;  
               }
        });  
    }  
}
`

好了,这个 RPC 框架就这样好了,是不是很简略?就是 调用者传递了办法名、参数类型和参数值,提供者接管到这样参数之后调用对于的办法返回后果就好了!这就是近程过程调用。

咱们来看看如何应用

`// 服务提供者只须要暴露出接口
       AobingService service = new AobingServiceImpl ();  
       AobingRpcFramework.export(service, 2333);  

       // 服务调用者只须要设置依赖
       AobingService service = AobingRpcFramework.refer(AobingService.class, “127.0.0.1”, 2333);  
       service.hello();`

看起来如同好不错哟,不过这很是简陋,用作 demo 有助了解还是极好的!

接下来就来看看 Dubbo 吧!上正菜!

Dubbo 简介

Dubbo 是阿里巴巴 2011 年开源的一个基于 Java 的 RPC 框架,两头寂静了一段时间,不过其余一些企业还在用 Dubbo 并本人做了扩大,比方当当网的 Dubbox,还有网易考拉的 Dubbok。

然而在 2017 年阿里巴巴又重启了对 Dubbo 保护。在 2017 年荣获了开源中国 2017 最受欢迎的中国开源软件 Top 3。

在 2018 年和 Dubbox 进行了合并,并且进入 Apache 孵化器,在 2019 年毕业正式成为 Apache 顶级我的项目。

目前 Dubbo 社区主力保护的是 2.6.x 和 2.7.x 两大版本,2.6.x 版本次要是 bug 修复和大量性能加强为准,是稳固版本。

而 2.7.x 是次要开发版本,更新和新增新的 feature 和优化,并且 2.7.5 版本的公布被 Dubbo 认为是里程碑式的版本公布,之后咱们再做剖析。

它实现了面向接口的代理 RPC 调用,并且能够配合 ZooKeeper 等组件实现服务注册和发现性能,并且领有负载平衡、容错机制等。

Dubbo 总体架构

咱们先来看下官网的一张图。

本丙再暖心的给上图内每个节点的角色阐明一下。

节点

角色阐明

Consumer

须要调用近程服务的服务生产方

Registry

注册核心

Provider

服务提供方

Container

服务运行的容器

Monitor

监控核心

我再来大抵说一下整体的流程,首先服务提供者 Provider 启动而后向注册核心注册 本人所能提供的服务。

服务消费者 Consumer 启动向注册核心订阅 本人所需的服务。而后注册核心将提供者元信息告诉给 Consumer,之后 Consumer 因为曾经从注册核心获取提供者的地址,因而能够 通过负载平衡抉择一个 Provider 间接调用

之后服务提供方元数据变更的话 注册核心会把变更推送给服务消费者

服务提供者和消费者都会在内存中记录着调用的次数和工夫,而后 定时的发送统计数据到监控核心

一些留神点

首先 注册核心和监控核心是可选的,你能够不要监控,也不要注册核心,间接在配置文件外面写而后提供方和生产方直连。

而后注册核心、提供方和生产方之间都是长连贯,和监控方不是长连贯,并且 生产方是间接调用提供方,不通过注册核心

就算 注册核心和监控核心宕机了也不会影响到曾经失常运行的提供者和消费者,因为消费者有本地缓存提供者的信息。

Dubbo 分层架构

总的而言 Dubbo 分为三层,如果每一层再细分上来,一共有十层。别怕也就十层,本丙带大家过一遍,大家先有个大抵的印象,之后的文章丙会带着大家再深刻。

大的三层别离为 Business(业务层)、RPC 层、Remoting,并且还分为 API 层和 SPI 层。

分为大三层其实就是和咱们晓得的网络分层一样的意思,只有层次分明,职责边界清晰能力更好的扩大

而分 API 层和 SPI 层这是 Dubbo 胜利的一点,采纳微内核设计 +SPI 扩大,使得有非凡需要的接入方能够自定义扩大,做定制的二次开发。

接下来咱们再来看看每一层都是干嘛的。

  • Service,业务层,就是咱们开发的业务逻辑层。
  • Config,配置层,次要围绕 ServiceConfig 和 ReferenceConfig,初始化配置信息。
  • Proxy,代理层,服务提供者还是消费者都会生成一个代理类,使得服务接口透明化,代理层做近程调用和返回后果。
  • Register,注册层,封装了服务注册和发现。
  • Cluster,路由和集群容错层,负责选取具体调用的节点,解决非凡的调用要求和负责近程调用失败的容错措施。
  • Monitor,监控层,负责监控统计调用工夫和次数。
  • Portocol,近程调用层,次要是封装 RPC 调用,次要负责管理 Invoker,Invoker 代表一个形象封装了的执行体,之后再做详解。
  • Exchange,信息替换层,用来封装申请响应模型,同步转异步。
  • Transport,网络传输层,形象了网络传输的对立接口,这样用户想用 Netty 就用 Netty,想用 Mina 就用 Mina。
  • Serialize,序列化层,将数据序列化成二进制流,当然也做反序列化。

SPI

我再略微提一下 SPI(Service Provider Interface),是 JDK 内置的一个服务发现机制,它使得接口和具体实现齐全解耦。咱们只申明接口,具体的实现类在配置中抉择。

具体的就是你定义了一个接口,而后在 META-INF/services 目录下 搁置一个与接口同名的文本文件 ,文件的内容为 接口的实现类,多个实现类用换行符分隔。

这样就通过配置来决定具体用哪个实现!

而 Dubbo SPI 还做了一些改良,篇幅无限留在之后再谈。

Dubbo 调用过程

下面我曾经介绍了每个层到底是干嘛的,咱们当初再来串起来走一遍调用的过程,加深你对 Dubbo 的了解,让知识点串起来,由点及面来一波连连看。

咱们先从服务提供者开始,看看它是如何工作的。

服务裸露过程

首先 Provider 启动,通过 Proxy 组件依据具体的协定 Protocol 将须要裸露进来的接口封装成 Invoker,Invoker 是 Dubbo 一个很外围的组件,代表一个可执行体。

而后再通过 Exporter 包装一下,这是为了在注册核心裸露本人套的一层,而后将 Exporter 通过 Registry 注册到注册核心。这就是整体服务裸露过程。

生产过程

接着咱们来看消费者调用流程(把服务者裸露的过程也在图里展现进去了,这个图其实算一个挺残缺的流程图了)。

首先消费者启动会向注册核心拉取服务提供者的元信息,而后调用流程也是从 Proxy 开始,毕竟都须要代理能力无感知。

Proxy 持有一个 Invoker 对象,调用 invoke 之后须要通过 Cluster 先从 Directory 获取所有可调用的近程服务的 Invoker 列表,如果配置了某些路由规定,比方某个接口只能调用某个节点的那就再过滤一遍 Invoker 列表。

剩下的 Invoker 再通过 LoadBalance 做负载平衡选取一个。而后再通过 Filter 做一些统计什么的,再通过 Client 做数据传输,比方用 Netty 来传输。

传输须要通过 Codec 接口做协定结构,再序列化。最终发往对应的服务提供者。

服务提供者接管到之后也会进行 Codec 协定解决,而后反序列化后将申请扔到线程池解决。某个线程会依据申请找到对应的 Exporter,而找到 Exporter 其实就是找到了 Invoker,然而还会有一层层 Filter,通过一层层过滤链之后最终调用实现类而后原路返回后果。

实现整个调用过程!

总结

这次敖丙带着大家先理解了下什么是 RPC,而后布局了一波 RPC 框架须要哪些组件,而后再用代码实现了一个简略的 RPC 框架。

而后带着大家理解了下 Dubbo 的倒退历史、总体架构、分层设计架构以及每个组件是干嘛的,再带着大伙走了一遍整体调用过程。

我真的是太暖了啊!

dubbo 近期我会安顿几个章节持续开展,最初会出一个面试版本的 dubbo,咱们刮目相待吧。

我是敖丙,你晓得的越多,你不晓得的越多,咱们下期见!

人才 们的 【三连】 就是敖丙创作的最大能源,如果本篇博客有任何谬误和倡议,欢送人才们留言!

退出移动版