RPC 通信流程

Posted Louis军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RPC 通信流程相关的知识,希望对你有一定的参考价值。


我们知道 RPC 是一个远程调用,那肯定就需要通过网络来传输数据,并且 RPC 常用于业务系统之间的数据交互,需要保证其可靠性,所以 RPC 一般默认采用 TCP 来传输。我们常用的 HTTP 协议也是建立在 TCP 之上的。

网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。对象是肯定没法直接在网络中传输的,需要提前把它转成可传输的二进制,并且要求转换算法是可逆的,这个过程我们一般叫做“序列化”。调用方持续地把请求参数序列化成二进制后,经过 TCP 传输给了服务提供方。服务提供方从 TCP 通道里面收到二进制数据,那如何知道一个请求的数据到哪里结束,是一个什么类型的请求呢?

我们把数据格式的约定内容叫做“协议”。

大多数的协议会分成两部分,分别是数据头和消息体。

数据头一般用于身份识别,包括协议标识、数据大小、请求类型、序列化类型等信息;消息体主要是请求的业务参数信息和扩展属性等。

根据协议格式,服务提供方就可以正确地从二进制数据中分割出不同的请求来,同时根据请求类型和序列化类型,把二进制的消息体逆向还原成请求对象。这个过程叫作“反序列化”。服务提供方再根据反序列化出来的请求对象找到对应的实现类,完成真正的方法调用,然后把执行结果序列化后,回写到对应的 TCP 通道里面。调用方获取到应答的数据包后,再反序列化成应答对象,这样调用方就完成了一次 RPC 调用。

对于研发人员来说,这样做要掌握太多的 RPC 底层细节,需要手动写代码去构造请求、调用序列化,并进行网络调用,整个 API 非常不友好。

那我们有什么办法来简化 API,屏蔽掉 RPC 细节,让使用方只需要关注业务接口,像调用本地一样来调用远程呢?

如果你了解 Spring,一定对其 AOP 技术很佩服,其核心是采用动态代理的技术,通过字节码增强对方法进行拦截增强,以便于增加需要的额外处理逻辑。

其实这个技术也可以应用到 RPC 场景来解决我们刚才面临的问题。

由服务提供者给出业务接口声明,在调用方的程序里面,RPC 框架根据调用的服务接口提前生成动态代理实现类,并通过依赖注入等技术注入到声明了该接口的相关业务逻辑里面。该代理实现类会拦截所有的方法调用,在提供的方法处理逻辑里面完成一整套的远程调用,并把远程调用结果返回给调用方,这样调用方在调用远程方法的时候就获得了像调用本地接口一样的体验。

到这里,一个简单版本的 RPC 框架就实现了。

整个流程图如下,供你参考:

所以,RPC 的作用体现在以下两个方面:

  1. 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法;

  2. 隐藏底层网络通信的复杂性,让我们更专注于业务逻辑。



以上是关于RPC 通信流程的主要内容,如果未能解决你的问题,请参考以下文章

dubbo 的工作原理?注册中心挂了可以通信吗? rpc 请求的流程是怎样的?dubbo 支持哪些通信协议以及序列化协议?

RPC 框架

RabbitMQ中RPC的实现及其通信机制

Web | RPC 的结构流程

Go微服务—— RPC

Go微服务—— RPC