用通俗的语言介绍 RPC 框架的架构原理

爱笑的架构师

共 2743字,需浏览 6分钟

 ·

2022-01-13 09:37

2022 年认真干点事!

动手实现一个简易的 RPC 轮子真的很难吗?no no no,很简单的,不信你把文章看完(doge)。

动动手

RPC 框架典型的架构

典型的 RPC 架构大致可以分为三个部分:

(1)服务提供者(RPC Server):运行在服务器端,提供服务接口定义与服务实现类。

(2)注册中心(Registry):运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。

(3)服务消费者(RPC Client):运行在客户端,通过远程代理对象调用远程服务。

通过上面的图可以看出,一次简单的 RPC 调用可以分为以下几个步骤:

(1)服务提供者启动后主动向服务注册中心注册机器ip、端口以及提供的服务列表;

(2)服务消费者启动时向服务注册中心获取服务提供方地址列表,在本地缓存一份;

(3)服务消费者通过本地调用的方式调用服务,调用模块收到请求后通过负载均衡策略选取合适的远程服务地址;

(4)协议模块负责将方法、入参等信息序列化(编码)成能够进行网络传输的消息体,并将消息通过网络发送给服务端;

(5)服务端收到消息后进行解码(反序列化操作)。

(6)根据解码结果调用本地的服务进行相关处理;

(7)服务端将处理返回的结果进行序列化(编码),并将结果通过网络发送至服务消费者;

(8)服务消费者收到消息后进行解码最终得到结果;

敲黑板:在不同的 RPC 框架实现中步骤 1、2、3的顺序可能有些不同。

RPC 核心功能

一个完整的商用 RPC 框架有很多功能,最最核心的基本就是三个:服务寻址数据编解码网络传输

服务寻址

如果是本地调用,被调用的方法在同一个进程内,操作系统或虚拟机可以地址空间找到;但是在远程调用中,这是行不通的,因为两个进程的地址空间是完全不一样的,并且也无法知道远端的进程在何处。

要想实现远程调用,我们需要对服务消费者和服务提供者进行约束:

  • 在远程过程调用中所有的函数都必须有一个ID,这个 ID 在整套系统中是唯一确定的。

  • 服务消费者在做远程过程调用时,发送的消息体中必须携带这个 ID。

  • 服务消费者和服务提供者分别维护一个函数和 ID 的对应表。

当服务消费者需要进行远程调用时,它就查一下这个表,找出对应的 ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。

上面说的可能比较抽象,通俗一点就是服务消费者如何寻找服务提供者,这就是服务寻址。


服务寻址的实现方式有很多种,比较常见的是:服务注册中心。要调用服务,首先你需要一个服务注册中心去查询对方服务都有哪些实例,然后根据负载均衡策略择优选一。

像 Dubbo 框架的服务注册中心是可以配置的,官方推荐使用 Zookeeper。

数据编解码(序列化和反序列化)

对计算机网络稍微有一点了解的同学都知道,数据在网络中传输是二进制的:01010101010101010,类似这种,只有二进制数据才能在网络中传输。

那一个客户端调用远程服务的一个方法,像方法入参这些必然需要转换成二进制才能进行传输,这种将对象转换成二进制流的过程就叫做序列化编码

服务端接收到二进制流不能识别,势必要将二进制流转换成对象,这个逆过程就叫做反序列化解码

一般场景下是可以将序列化编码简称为序列化。

敲黑板:

如果非要较真,严格来说序列化和编码是两个不同的概念,我画一张图大家都明白了。

序列化和编码的对比

序列化+编码的逆过程就是:解码+反序列化。

网络传输

提起网络传输大家脑海里肯定马上就能想到 TCP/IP四层模型、OSI 七层模型,那通常 RPC 会选择那一层作为传输协议呢?

在回答这个问题前我们先看下 RPC 需要网络传输实现什么功能。

客户端的数据经过序列化+编码后,就需要通过网络传输到服务端。网络传输层需要把前面说的函数 ID 和序列化后的参数字节流传给服务端,服务端处理完然后再把序列化后的调用结果传回客户端。

原则上只要能实现上面这个功能的都可以作为传输层来使用,具体协议没有限制。

我们先来看下 TCP 协议,TCP 连接可以是按需连接,需要调用的时候就先建立连接,调用结束后就立马断掉,也可以是长连接,客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效。

由此可见 TCP 的性能确实很好,因此市面上大部分 RPC 框架都使用 TCP 协议,但也有少部分框架使用其他协议,比如 gRPC 就基于 HTTP2 来实现的。

敲黑板:

数据编解码和网络传输可以有多种组合方式,比如常见的有:HTTP+JSON, Dubbo 协议+TCP 等。

常见的 RPC 框架

说了这么多 RPC 相关的技术,我们盘点一下市面上常用的 RPC 框架。

  • RMI(Sun/Oracle)
  • Thrift(Facebook/Apache)
  • gRPC(Google)
  • Finagle(Twitter)
  • Dubbo(阿里巴巴/Apache)
  • Motan(新浪微博)
  • brpc(百度/Apache)
  • ……欢迎大家补充其他的。

总结

(1)服务提供者需要以某种形式提供服务调用相关的信息,包括但不限于服务接口定义、数据结构、或者中间态的服务定义文件。例如Facebook的 Thrift 框架的IDL文件,Web service的 WSDL 文件;服务的消费者需要通过一定的场景获取远程服务调用相关的信息。

(2)远程代理对象:服务消费者用的服务实际是远程服务的本地代理,说白了就是通过动态代理来实现的。

(3)序列化:毕竟是远程通信,需要将对象转化成二进制流进行传输。不同的RPC框架应用的场景不同,在序列化上也会采取不同的技术。

(4)通信:RPC框架与具体的协议无关。Netty 是一个高性能的网络通信框架。

因此要实现一个 RPC 框架,只需要把上面四点实现了就基本完成了。大家学会了吗?

-- END --

前段时间我动手撸了一个 RPC 框架demo,欢迎大家去下载源码试用。

如果你对这个项目还不是很熟悉,建议你先看一下下面的入门文章。

 RPC 01 

 RPC 02 

 RPC 03 

 RPC 04 手绘4 张图带你入门 RPC 服务框架


我是雷小帅,记得三连,下期见~

浏览 47
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报