发布时间:2023-01-23 文章分类:编程知识 投稿人:王小丽 字号: 默认 | | 超大 打印

07 | 架构设计:设计一个灵活的RPC框架

RPC就是把拦截到的方法参数,转成可以在网络中传输的二进制,并保证在服务提供方能正确地还原出语义,最终实现像调用本地一样地调用远程的目的。
RPC的本质是一个远程调用,需要通过网络来传输数据,我们一般采用TCP协议作为数据通信协议,为了屏蔽网络传输的复杂性,我们需要封装一个独立的数据传输模块来收发二进制数据,这个模块被称为传输模块

我们在调用方法时,方法的出入参数都是对象数据,我们需要将对象转换成二进制,即进行序列化操作,同时,我们还需要在方法调用参数的二进制数据后面增加“断句”符号来分隔出不同的请求,这个过程被称为协议封装

传输模块和协议封装都是为了保证数据在网络中可以正确传输,我们将这两个模块放在一起,称为协议模块

我们还可以在协议模块中添加压缩功能,在方法调用参数或者返回值的二进制数据大于某个阈值时,我们使用压缩框架对数据进行无损压缩,然后再另外一段使用同样的压缩机制进行解压处理,保证数据可以还原。

传输模块和协议模块是RPC中最基础的功能,它们使得对象可以正确的传输到服务提供方。但是为了让这两个模块可以同时工作,我们还需要手写一些粘合代码,这些代码对于RPC框架的使用者来说是没有意义的,属于重复工作,我们将这些事情进行封装处理,形成RPC调用的入口,一般称为Bootstrap模块

什么是”服务发现“?

针对同一个接口有多个服务提供者,但这多个服务提供者对于我们的调用方来说是透明的,所以在RPC里面我们还需要给调用方找到所有的服务提供方,并需要在RPC里面维护好接口和服务提供者地址间的关系,这样调用方在发起请求时才能快速找到对应的接收地址。

一个划分为四层的RPC基础架构的示意图如下。

《RPC实战与核心原理》学习笔记Day6

上面的框架有什么问题吗?最主要的问题就是扩展性不高,当我们有需求变更时,很容易需要大范围调整框架。

我们可以尝试使用插件化架构的方法论来优化我们的RPC架构。

我们怎么在RPC框架里面支持插件化架构?

我们可以将每个功能点抽象成一个接口,将这个接口作为插件的契约,然后把这个功能的接口与功能的实现分离,并提供接口的默认实现。

加入插件功能后,RPC框架就包含了两大核心体系:核心功能体系插件体系,示意图如下。

《RPC实战与核心原理》学习笔记Day6

彩蛋 - Java SPI

什么是Java SPI?

SPI(Service Provider Interface)是JDK内置的一种服务提供发现机制,可以用来扩展框架和替换组件,它的核心思想是解耦

例如针对DB驱动程序,java.sql.Driver接口定义了相关规范,不同的厂家会针对这一规范提供不同的实现,例如MySQL和PostgreSQL会提供不同的实现给用户。

SPI和API有什么区别?

SPI的使用流程是怎样的?

  1. 相关组织或者公司发布接口规范定义。
  2. 第三方根据接口提供具体实现。
  3. 开发者在程序中针对SPI进行配置并使用。

JDK提供的SPI有哪些不足?

  1. 不能按需加载,需要遍历所有的实现,并实例化,然后才能在循环中找到我们需要的实现。
  2. 获取某个实现类的方式不够灵活。
  3. 多个并发多线程使用ServiceLoader类的实例是不安全的。